Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendevice.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2002 Lionel Ulmer 00003 * Copyright 2002-2005 Jason Edmeades 00004 * Copyright 2003-2004 Raphael Junqueira 00005 * Copyright 2004 Christian Costa 00006 * Copyright 2005 Oliver Stieber 00007 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers 00008 * Copyright 2006-2008 Henri Verbeet 00009 * Copyright 2007 Andrew Riedi 00010 * Copyright 2009-2011 Henri Verbeet for CodeWeavers 00011 * 00012 * This library is free software; you can redistribute it and/or 00013 * modify it under the terms of the GNU Lesser General Public 00014 * License as published by the Free Software Foundation; either 00015 * version 2.1 of the License, or (at your option) any later version. 00016 * 00017 * This library is distributed in the hope that it will be useful, 00018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00020 * Lesser General Public License for more details. 00021 * 00022 * You should have received a copy of the GNU Lesser General Public 00023 * License along with this library; if not, write to the Free Software 00024 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00025 */ 00026 00027 #include "config.h" 00028 #include <stdio.h> 00029 #ifdef HAVE_FLOAT_H 00030 # include <float.h> 00031 #endif 00032 #include "wined3d_private.h" 00033 00034 WINE_DEFAULT_DEBUG_CHANNEL(d3d); 00035 00036 /* Define the default light parameters as specified by MSDN. */ 00037 const struct wined3d_light WINED3D_default_light = 00038 { 00039 WINED3D_LIGHT_DIRECTIONAL, /* Type */ 00040 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */ 00041 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */ 00042 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */ 00043 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */ 00044 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */ 00045 0.0f, /* Range */ 00046 0.0f, /* Falloff */ 00047 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */ 00048 0.0f, /* Theta */ 00049 0.0f /* Phi */ 00050 }; 00051 00052 /********************************************************** 00053 * Global variable / Constants follow 00054 **********************************************************/ 00055 const float identity[] = 00056 { 00057 1.0f, 0.0f, 0.0f, 0.0f, 00058 0.0f, 1.0f, 0.0f, 0.0f, 00059 0.0f, 0.0f, 1.0f, 0.0f, 00060 0.0f, 0.0f, 0.0f, 1.0f, 00061 }; /* When needed for comparisons */ 00062 00063 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these 00064 * actually have the same values in GL and D3D. */ 00065 static GLenum gl_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type) 00066 { 00067 switch(primitive_type) 00068 { 00069 case WINED3D_PT_POINTLIST: 00070 return GL_POINTS; 00071 00072 case WINED3D_PT_LINELIST: 00073 return GL_LINES; 00074 00075 case WINED3D_PT_LINESTRIP: 00076 return GL_LINE_STRIP; 00077 00078 case WINED3D_PT_TRIANGLELIST: 00079 return GL_TRIANGLES; 00080 00081 case WINED3D_PT_TRIANGLESTRIP: 00082 return GL_TRIANGLE_STRIP; 00083 00084 case WINED3D_PT_TRIANGLEFAN: 00085 return GL_TRIANGLE_FAN; 00086 00087 case WINED3D_PT_LINELIST_ADJ: 00088 return GL_LINES_ADJACENCY_ARB; 00089 00090 case WINED3D_PT_LINESTRIP_ADJ: 00091 return GL_LINE_STRIP_ADJACENCY_ARB; 00092 00093 case WINED3D_PT_TRIANGLELIST_ADJ: 00094 return GL_TRIANGLES_ADJACENCY_ARB; 00095 00096 case WINED3D_PT_TRIANGLESTRIP_ADJ: 00097 return GL_TRIANGLE_STRIP_ADJACENCY_ARB; 00098 00099 default: 00100 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type)); 00101 return GL_NONE; 00102 } 00103 } 00104 00105 static enum wined3d_primitive_type d3d_primitive_type_from_gl(GLenum primitive_type) 00106 { 00107 switch(primitive_type) 00108 { 00109 case GL_POINTS: 00110 return WINED3D_PT_POINTLIST; 00111 00112 case GL_LINES: 00113 return WINED3D_PT_LINELIST; 00114 00115 case GL_LINE_STRIP: 00116 return WINED3D_PT_LINESTRIP; 00117 00118 case GL_TRIANGLES: 00119 return WINED3D_PT_TRIANGLELIST; 00120 00121 case GL_TRIANGLE_STRIP: 00122 return WINED3D_PT_TRIANGLESTRIP; 00123 00124 case GL_TRIANGLE_FAN: 00125 return WINED3D_PT_TRIANGLEFAN; 00126 00127 case GL_LINES_ADJACENCY_ARB: 00128 return WINED3D_PT_LINELIST_ADJ; 00129 00130 case GL_LINE_STRIP_ADJACENCY_ARB: 00131 return WINED3D_PT_LINESTRIP_ADJ; 00132 00133 case GL_TRIANGLES_ADJACENCY_ARB: 00134 return WINED3D_PT_TRIANGLELIST_ADJ; 00135 00136 case GL_TRIANGLE_STRIP_ADJACENCY_ARB: 00137 return WINED3D_PT_TRIANGLESTRIP_ADJ; 00138 00139 default: 00140 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type)); 00141 return WINED3D_PT_UNDEFINED; 00142 } 00143 } 00144 00145 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum) 00146 { 00147 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && !usage_idx) 00148 *regnum = WINED3D_FFP_POSITION; 00149 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && !usage_idx) 00150 *regnum = WINED3D_FFP_BLENDWEIGHT; 00151 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && !usage_idx) 00152 *regnum = WINED3D_FFP_BLENDINDICES; 00153 else if (usage == WINED3DDECLUSAGE_NORMAL && !usage_idx) 00154 *regnum = WINED3D_FFP_NORMAL; 00155 else if (usage == WINED3DDECLUSAGE_PSIZE && !usage_idx) 00156 *regnum = WINED3D_FFP_PSIZE; 00157 else if (usage == WINED3DDECLUSAGE_COLOR && !usage_idx) 00158 *regnum = WINED3D_FFP_DIFFUSE; 00159 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1) 00160 *regnum = WINED3D_FFP_SPECULAR; 00161 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD) 00162 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx; 00163 else 00164 { 00165 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx); 00166 *regnum = ~0U; 00167 return FALSE; 00168 } 00169 00170 return TRUE; 00171 } 00172 00173 /* Context activation is done by the caller. */ 00174 void device_stream_info_from_declaration(struct wined3d_device *device, 00175 struct wined3d_stream_info *stream_info, BOOL *fixup) 00176 { 00177 const struct wined3d_state *state = &device->stateBlock->state; 00178 /* We need to deal with frequency data! */ 00179 struct wined3d_vertex_declaration *declaration = state->vertex_declaration; 00180 BOOL use_vshader; 00181 unsigned int i; 00182 00183 stream_info->use_map = 0; 00184 stream_info->swizzle_map = 0; 00185 00186 /* Check for transformed vertices, disable vertex shader if present. */ 00187 stream_info->position_transformed = declaration->position_transformed; 00188 use_vshader = state->vertex_shader && !declaration->position_transformed; 00189 00190 /* Translate the declaration into strided data. */ 00191 for (i = 0; i < declaration->element_count; ++i) 00192 { 00193 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i]; 00194 const struct wined3d_stream_state *stream = &state->streams[element->input_slot]; 00195 struct wined3d_buffer *buffer = stream->buffer; 00196 struct wined3d_bo_address data; 00197 BOOL stride_used; 00198 unsigned int idx; 00199 DWORD stride; 00200 00201 TRACE("%p Element %p (%u of %u)\n", declaration->elements, 00202 element, i + 1, declaration->element_count); 00203 00204 if (!buffer) continue; 00205 00206 data.buffer_object = 0; 00207 data.addr = NULL; 00208 00209 stride = stream->stride; 00210 if (state->user_stream) 00211 { 00212 TRACE("Stream %u is UP, %p\n", element->input_slot, buffer); 00213 data.buffer_object = 0; 00214 data.addr = (BYTE *)buffer; 00215 } 00216 else 00217 { 00218 TRACE("Stream %u isn't UP, %p\n", element->input_slot, buffer); 00219 buffer_get_memory(buffer, &device->adapter->gl_info, &data); 00220 00221 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets 00222 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory 00223 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap 00224 * around to some big value. Hope that with the indices, the driver wraps it back internally. If 00225 * not, drawStridedSlow is needed, including a vertex buffer path. */ 00226 if (state->load_base_vertex_index < 0) 00227 { 00228 WARN("load_base_vertex_index is < 0 (%d), not using VBOs.\n", 00229 state->load_base_vertex_index); 00230 data.buffer_object = 0; 00231 data.addr = buffer_get_sysmem(buffer, &device->adapter->gl_info); 00232 if ((UINT_PTR)data.addr < -state->load_base_vertex_index * stride) 00233 { 00234 FIXME("System memory vertex data load offset is negative!\n"); 00235 } 00236 } 00237 00238 if (fixup) 00239 { 00240 if (data.buffer_object) 00241 *fixup = TRUE; 00242 else if (*fixup && !use_vshader 00243 && (element->usage == WINED3DDECLUSAGE_COLOR 00244 || element->usage == WINED3DDECLUSAGE_POSITIONT)) 00245 { 00246 static BOOL warned = FALSE; 00247 if (!warned) 00248 { 00249 /* This may be bad with the fixed function pipeline. */ 00250 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n"); 00251 warned = TRUE; 00252 } 00253 } 00254 } 00255 } 00256 data.addr += element->offset; 00257 00258 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx); 00259 00260 if (use_vshader) 00261 { 00262 if (element->output_slot == ~0U) 00263 { 00264 /* TODO: Assuming vertexdeclarations are usually used with the 00265 * same or a similar shader, it might be worth it to store the 00266 * last used output slot and try that one first. */ 00267 stride_used = vshader_get_input(state->vertex_shader, 00268 element->usage, element->usage_idx, &idx); 00269 } 00270 else 00271 { 00272 idx = element->output_slot; 00273 stride_used = TRUE; 00274 } 00275 } 00276 else 00277 { 00278 if (!element->ffp_valid) 00279 { 00280 WARN("Skipping unsupported fixed function element of format %s and usage %s\n", 00281 debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage)); 00282 stride_used = FALSE; 00283 } 00284 else 00285 { 00286 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx); 00287 } 00288 } 00289 00290 if (stride_used) 00291 { 00292 TRACE("Load %s array %u [usage %s, usage_idx %u, " 00293 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n", 00294 use_vshader ? "shader": "fixed function", idx, 00295 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot, 00296 element->offset, stride, debug_d3dformat(element->format->id), data.buffer_object); 00297 00298 data.addr += stream->offset; 00299 00300 stream_info->elements[idx].format = element->format; 00301 stream_info->elements[idx].data = data; 00302 stream_info->elements[idx].stride = stride; 00303 stream_info->elements[idx].stream_idx = element->input_slot; 00304 00305 if (!device->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA] 00306 && element->format->id == WINED3DFMT_B8G8R8A8_UNORM) 00307 { 00308 stream_info->swizzle_map |= 1 << idx; 00309 } 00310 stream_info->use_map |= 1 << idx; 00311 } 00312 } 00313 00314 device->num_buffer_queries = 0; 00315 if (!state->user_stream) 00316 { 00317 WORD map = stream_info->use_map; 00318 00319 /* PreLoad all the vertex buffers. */ 00320 for (i = 0; map; map >>= 1, ++i) 00321 { 00322 struct wined3d_stream_info_element *element; 00323 struct wined3d_buffer *buffer; 00324 00325 if (!(map & 1)) continue; 00326 00327 element = &stream_info->elements[i]; 00328 buffer = state->streams[element->stream_idx].buffer; 00329 wined3d_buffer_preload(buffer); 00330 00331 /* If the preload dropped the buffer object, update the stream info. */ 00332 if (buffer->buffer_object != element->data.buffer_object) 00333 { 00334 element->data.buffer_object = 0; 00335 element->data.addr = buffer_get_sysmem(buffer, &device->adapter->gl_info) 00336 + (ptrdiff_t)element->data.addr; 00337 } 00338 00339 if (buffer->query) 00340 device->buffer_queries[device->num_buffer_queries++] = buffer->query; 00341 } 00342 } 00343 } 00344 00345 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info, 00346 const struct wined3d_strided_element *strided, struct wined3d_stream_info_element *e) 00347 { 00348 e->data.addr = strided->data; 00349 e->data.buffer_object = 0; 00350 e->format = wined3d_get_format(gl_info, strided->format); 00351 e->stride = strided->stride; 00352 e->stream_idx = 0; 00353 } 00354 00355 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info, 00356 const struct wined3d_strided_data *strided, struct wined3d_stream_info *stream_info) 00357 { 00358 unsigned int i; 00359 00360 memset(stream_info, 0, sizeof(*stream_info)); 00361 00362 if (strided->position.data) 00363 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]); 00364 if (strided->normal.data) 00365 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]); 00366 if (strided->diffuse.data) 00367 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]); 00368 if (strided->specular.data) 00369 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]); 00370 00371 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i) 00372 { 00373 if (strided->tex_coords[i].data) 00374 stream_info_element_from_strided(gl_info, &strided->tex_coords[i], 00375 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]); 00376 } 00377 00378 stream_info->position_transformed = strided->position_transformed; 00379 00380 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i) 00381 { 00382 if (!stream_info->elements[i].format) continue; 00383 00384 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA] 00385 && stream_info->elements[i].format->id == WINED3DFMT_B8G8R8A8_UNORM) 00386 { 00387 stream_info->swizzle_map |= 1 << i; 00388 } 00389 stream_info->use_map |= 1 << i; 00390 } 00391 } 00392 00393 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info) 00394 { 00395 TRACE("Strided Data:\n"); 00396 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION); 00397 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT); 00398 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES); 00399 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL); 00400 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE); 00401 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE); 00402 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR); 00403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0); 00404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1); 00405 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2); 00406 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3); 00407 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4); 00408 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5); 00409 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6); 00410 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7); 00411 } 00412 00413 /* Context activation is done by the caller. */ 00414 void device_update_stream_info(struct wined3d_device *device, const struct wined3d_gl_info *gl_info) 00415 { 00416 struct wined3d_stream_info *stream_info = &device->strided_streams; 00417 const struct wined3d_state *state = &device->stateBlock->state; 00418 BOOL fixup = FALSE; 00419 00420 if (device->up_strided) 00421 { 00422 /* Note: this is a ddraw fixed-function code path. */ 00423 TRACE("=============================== Strided Input ================================\n"); 00424 device_stream_info_from_strided(gl_info, device->up_strided, stream_info); 00425 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info); 00426 } 00427 else 00428 { 00429 TRACE("============================= Vertex Declaration =============================\n"); 00430 device_stream_info_from_declaration(device, stream_info, &fixup); 00431 } 00432 00433 if (state->vertex_shader && !stream_info->position_transformed) 00434 { 00435 if (state->vertex_declaration->half_float_conv_needed && !fixup) 00436 { 00437 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n"); 00438 device->useDrawStridedSlow = TRUE; 00439 } 00440 else 00441 { 00442 device->useDrawStridedSlow = FALSE; 00443 } 00444 } 00445 else 00446 { 00447 WORD slow_mask = (1 << WINED3D_FFP_PSIZE); 00448 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA] 00449 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR)); 00450 00451 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup) 00452 { 00453 device->useDrawStridedSlow = TRUE; 00454 } 00455 else 00456 { 00457 device->useDrawStridedSlow = FALSE; 00458 } 00459 } 00460 } 00461 00462 static void device_preload_texture(const struct wined3d_state *state, unsigned int idx) 00463 { 00464 struct wined3d_texture *texture; 00465 enum WINED3DSRGB srgb; 00466 00467 if (!(texture = state->textures[idx])) return; 00468 srgb = state->sampler_states[idx][WINED3D_SAMP_SRGB_TEXTURE] ? SRGB_SRGB : SRGB_RGB; 00469 texture->texture_ops->texture_preload(texture, srgb); 00470 } 00471 00472 void device_preload_textures(const struct wined3d_device *device) 00473 { 00474 const struct wined3d_state *state = &device->stateBlock->state; 00475 unsigned int i; 00476 00477 if (use_vs(state)) 00478 { 00479 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) 00480 { 00481 if (state->vertex_shader->reg_maps.sampler_type[i]) 00482 device_preload_texture(state, MAX_FRAGMENT_SAMPLERS + i); 00483 } 00484 } 00485 00486 if (use_ps(state)) 00487 { 00488 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) 00489 { 00490 if (state->pixel_shader->reg_maps.sampler_type[i]) 00491 device_preload_texture(state, i); 00492 } 00493 } 00494 else 00495 { 00496 WORD ffu_map = device->fixed_function_usage_map; 00497 00498 for (i = 0; ffu_map; ffu_map >>= 1, ++i) 00499 { 00500 if (ffu_map & 1) 00501 device_preload_texture(state, i); 00502 } 00503 } 00504 } 00505 00506 BOOL device_context_add(struct wined3d_device *device, struct wined3d_context *context) 00507 { 00508 struct wined3d_context **new_array; 00509 00510 TRACE("Adding context %p.\n", context); 00511 00512 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array)); 00513 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, 00514 sizeof(*new_array) * (device->context_count + 1)); 00515 00516 if (!new_array) 00517 { 00518 ERR("Failed to grow the context array.\n"); 00519 return FALSE; 00520 } 00521 00522 new_array[device->context_count++] = context; 00523 device->contexts = new_array; 00524 return TRUE; 00525 } 00526 00527 void device_context_remove(struct wined3d_device *device, struct wined3d_context *context) 00528 { 00529 struct wined3d_context **new_array; 00530 BOOL found = FALSE; 00531 UINT i; 00532 00533 TRACE("Removing context %p.\n", context); 00534 00535 for (i = 0; i < device->context_count; ++i) 00536 { 00537 if (device->contexts[i] == context) 00538 { 00539 found = TRUE; 00540 break; 00541 } 00542 } 00543 00544 if (!found) 00545 { 00546 ERR("Context %p doesn't exist in context array.\n", context); 00547 return; 00548 } 00549 00550 if (!--device->context_count) 00551 { 00552 HeapFree(GetProcessHeap(), 0, device->contexts); 00553 device->contexts = NULL; 00554 return; 00555 } 00556 00557 memmove(&device->contexts[i], &device->contexts[i + 1], (device->context_count - i) * sizeof(*device->contexts)); 00558 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->context_count * sizeof(*device->contexts)); 00559 if (!new_array) 00560 { 00561 ERR("Failed to shrink context array. Oh well.\n"); 00562 return; 00563 } 00564 00565 device->contexts = new_array; 00566 } 00567 00568 /* Do not call while under the GL lock. */ 00569 void device_switch_onscreen_ds(struct wined3d_device *device, 00570 struct wined3d_context *context, struct wined3d_surface *depth_stencil) 00571 { 00572 if (device->onscreen_depth_stencil) 00573 { 00574 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_INTEXTURE); 00575 00576 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_INTEXTURE, 00577 device->onscreen_depth_stencil->ds_current_size.cx, 00578 device->onscreen_depth_stencil->ds_current_size.cy); 00579 wined3d_surface_decref(device->onscreen_depth_stencil); 00580 } 00581 device->onscreen_depth_stencil = depth_stencil; 00582 wined3d_surface_incref(device->onscreen_depth_stencil); 00583 } 00584 00585 static BOOL is_full_clear(const struct wined3d_surface *target, const RECT *draw_rect, const RECT *clear_rect) 00586 { 00587 /* partial draw rect */ 00588 if (draw_rect->left || draw_rect->top 00589 || draw_rect->right < target->resource.width 00590 || draw_rect->bottom < target->resource.height) 00591 return FALSE; 00592 00593 /* partial clear rect */ 00594 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0 00595 || clear_rect->right < target->resource.width 00596 || clear_rect->bottom < target->resource.height)) 00597 return FALSE; 00598 00599 return TRUE; 00600 } 00601 00602 static void prepare_ds_clear(struct wined3d_surface *ds, struct wined3d_context *context, 00603 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect, RECT *out_rect) 00604 { 00605 RECT current_rect, r; 00606 00607 if (ds->flags & location) 00608 SetRect(¤t_rect, 0, 0, 00609 ds->ds_current_size.cx, 00610 ds->ds_current_size.cy); 00611 else 00612 SetRectEmpty(¤t_rect); 00613 00614 IntersectRect(&r, draw_rect, ¤t_rect); 00615 if (EqualRect(&r, draw_rect)) 00616 { 00617 /* current_rect ⊇ draw_rect, modify only. */ 00618 SetRect(out_rect, 0, 0, ds->ds_current_size.cx, ds->ds_current_size.cy); 00619 return; 00620 } 00621 00622 if (EqualRect(&r, ¤t_rect)) 00623 { 00624 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */ 00625 00626 if (!clear_rect) 00627 { 00628 /* Full clear, modify only. */ 00629 *out_rect = *draw_rect; 00630 return; 00631 } 00632 00633 IntersectRect(&r, draw_rect, clear_rect); 00634 if (EqualRect(&r, draw_rect)) 00635 { 00636 /* clear_rect ⊇ draw_rect, modify only. */ 00637 *out_rect = *draw_rect; 00638 return; 00639 } 00640 } 00641 00642 /* Full load. */ 00643 surface_load_ds_location(ds, context, location); 00644 SetRect(out_rect, 0, 0, ds->ds_current_size.cx, ds->ds_current_size.cy); 00645 } 00646 00647 /* Do not call while under the GL lock. */ 00648 HRESULT device_clear_render_targets(struct wined3d_device *device, UINT rt_count, const struct wined3d_fb_state *fb, 00649 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags, const struct wined3d_color *color, 00650 float depth, DWORD stencil) 00651 { 00652 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL; 00653 struct wined3d_surface *target = rt_count ? fb->render_targets[0] : NULL; 00654 UINT drawable_width, drawable_height; 00655 struct wined3d_context *context; 00656 GLbitfield clear_mask = 0; 00657 BOOL render_offscreen; 00658 unsigned int i; 00659 RECT ds_rect; 00660 00661 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the 00662 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true 00663 * for the cleared parts, and the untouched parts. 00664 * 00665 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten 00666 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set 00667 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother 00668 * checking all this if the dest surface is in the drawable anyway. */ 00669 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect)) 00670 { 00671 for (i = 0; i < rt_count; ++i) 00672 { 00673 struct wined3d_surface *rt = fb->render_targets[i]; 00674 if (rt) 00675 surface_load_location(rt, rt->draw_binding, NULL); 00676 } 00677 } 00678 00679 context = context_acquire(device, target); 00680 if (!context->valid) 00681 { 00682 context_release(context); 00683 WARN("Invalid context, skipping clear.\n"); 00684 return WINED3D_OK; 00685 } 00686 00687 if (target) 00688 { 00689 render_offscreen = context->render_offscreen; 00690 target->get_drawable_size(context, &drawable_width, &drawable_height); 00691 } 00692 else 00693 { 00694 render_offscreen = TRUE; 00695 drawable_width = fb->depth_stencil->pow2Width; 00696 drawable_height = fb->depth_stencil->pow2Height; 00697 } 00698 00699 if (flags & WINED3DCLEAR_ZBUFFER) 00700 { 00701 DWORD location = render_offscreen ? fb->depth_stencil->draw_binding : SFLAG_INDRAWABLE; 00702 00703 if (!render_offscreen && fb->depth_stencil != device->onscreen_depth_stencil) 00704 device_switch_onscreen_ds(device, context, fb->depth_stencil); 00705 prepare_ds_clear(fb->depth_stencil, context, location, 00706 draw_rect, rect_count, clear_rect, &ds_rect); 00707 } 00708 00709 if (!context_apply_clear_state(context, device, rt_count, fb)) 00710 { 00711 context_release(context); 00712 WARN("Failed to apply clear state, skipping clear.\n"); 00713 return WINED3D_OK; 00714 } 00715 00716 ENTER_GL(); 00717 00718 /* Only set the values up once, as they are not changing. */ 00719 if (flags & WINED3DCLEAR_STENCIL) 00720 { 00721 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE]) 00722 { 00723 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); 00724 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE)); 00725 } 00726 glStencilMask(~0U); 00727 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK)); 00728 glClearStencil(stencil); 00729 checkGLcall("glClearStencil"); 00730 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT; 00731 } 00732 00733 if (flags & WINED3DCLEAR_ZBUFFER) 00734 { 00735 DWORD location = render_offscreen ? fb->depth_stencil->draw_binding : SFLAG_INDRAWABLE; 00736 00737 surface_modify_ds_location(fb->depth_stencil, location, ds_rect.right, ds_rect.bottom); 00738 00739 glDepthMask(GL_TRUE); 00740 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE)); 00741 glClearDepth(depth); 00742 checkGLcall("glClearDepth"); 00743 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT; 00744 } 00745 00746 if (flags & WINED3DCLEAR_TARGET) 00747 { 00748 for (i = 0; i < rt_count; ++i) 00749 { 00750 struct wined3d_surface *rt = fb->render_targets[i]; 00751 00752 if (rt) 00753 surface_modify_location(rt, rt->draw_binding, TRUE); 00754 } 00755 00756 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 00757 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE)); 00758 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1)); 00759 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2)); 00760 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3)); 00761 glClearColor(color->r, color->g, color->b, color->a); 00762 checkGLcall("glClearColor"); 00763 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT; 00764 } 00765 00766 if (!clear_rect) 00767 { 00768 if (render_offscreen) 00769 { 00770 glScissor(draw_rect->left, draw_rect->top, 00771 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top); 00772 } 00773 else 00774 { 00775 glScissor(draw_rect->left, drawable_height - draw_rect->bottom, 00776 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top); 00777 } 00778 checkGLcall("glScissor"); 00779 glClear(clear_mask); 00780 checkGLcall("glClear"); 00781 } 00782 else 00783 { 00784 RECT current_rect; 00785 00786 /* Now process each rect in turn. */ 00787 for (i = 0; i < rect_count; ++i) 00788 { 00789 /* Note that GL uses lower left, width/height. */ 00790 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]); 00791 00792 TRACE("clear_rect[%u] %s, current_rect %s.\n", i, 00793 wine_dbgstr_rect(&clear_rect[i]), 00794 wine_dbgstr_rect(¤t_rect)); 00795 00796 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently. 00797 * The rectangle is not cleared, no error is returned, but further rectangles are 00798 * still cleared if they are valid. */ 00799 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom) 00800 { 00801 TRACE("Rectangle with negative dimensions, ignoring.\n"); 00802 continue; 00803 } 00804 00805 if (render_offscreen) 00806 { 00807 glScissor(current_rect.left, current_rect.top, 00808 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top); 00809 } 00810 else 00811 { 00812 glScissor(current_rect.left, drawable_height - current_rect.bottom, 00813 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top); 00814 } 00815 checkGLcall("glScissor"); 00816 00817 glClear(clear_mask); 00818 checkGLcall("glClear"); 00819 } 00820 } 00821 00822 LEAVE_GL(); 00823 00824 if (wined3d_settings.strict_draw_ordering || (flags & WINED3DCLEAR_TARGET 00825 && target->container.type == WINED3D_CONTAINER_SWAPCHAIN 00826 && target->container.u.swapchain->front_buffer == target)) 00827 wglFlush(); /* Flush to ensure ordering across contexts. */ 00828 00829 context_release(context); 00830 00831 return WINED3D_OK; 00832 } 00833 00834 ULONG CDECL wined3d_device_incref(struct wined3d_device *device) 00835 { 00836 ULONG refcount = InterlockedIncrement(&device->ref); 00837 00838 TRACE("%p increasing refcount to %u.\n", device, refcount); 00839 00840 return refcount; 00841 } 00842 00843 ULONG CDECL wined3d_device_decref(struct wined3d_device *device) 00844 { 00845 ULONG refcount = InterlockedDecrement(&device->ref); 00846 00847 TRACE("%p decreasing refcount to %u.\n", device, refcount); 00848 00849 if (!refcount) 00850 { 00851 struct wined3d_stateblock *stateblock; 00852 UINT i; 00853 00854 if (wined3d_stateblock_decref(device->updateStateBlock) 00855 && device->updateStateBlock != device->stateBlock) 00856 FIXME("Something's still holding the update stateblock.\n"); 00857 device->updateStateBlock = NULL; 00858 00859 stateblock = device->stateBlock; 00860 device->stateBlock = NULL; 00861 if (wined3d_stateblock_decref(stateblock)) 00862 FIXME("Something's still holding the stateblock.\n"); 00863 00864 for (i = 0; i < sizeof(device->multistate_funcs) / sizeof(device->multistate_funcs[0]); ++i) 00865 { 00866 HeapFree(GetProcessHeap(), 0, device->multistate_funcs[i]); 00867 device->multistate_funcs[i] = NULL; 00868 } 00869 00870 if (!list_empty(&device->resources)) 00871 { 00872 struct wined3d_resource *resource; 00873 00874 FIXME("Device released with resources still bound, acceptable but unexpected.\n"); 00875 00876 LIST_FOR_EACH_ENTRY(resource, &device->resources, struct wined3d_resource, resource_list_entry) 00877 { 00878 FIXME("Leftover resource %p with type %s (%#x).\n", 00879 resource, debug_d3dresourcetype(resource->type), resource->type); 00880 } 00881 } 00882 00883 if (device->contexts) 00884 ERR("Context array not freed!\n"); 00885 if (device->hardwareCursor) 00886 DestroyCursor(device->hardwareCursor); 00887 device->hardwareCursor = 0; 00888 00889 wined3d_decref(device->wined3d); 00890 device->wined3d = NULL; 00891 HeapFree(GetProcessHeap(), 0, device); 00892 TRACE("Freed device %p.\n", device); 00893 } 00894 00895 return refcount; 00896 } 00897 00898 UINT CDECL wined3d_device_get_swapchain_count(const struct wined3d_device *device) 00899 { 00900 TRACE("device %p.\n", device); 00901 00902 return device->swapchain_count; 00903 } 00904 00905 HRESULT CDECL wined3d_device_get_swapchain(const struct wined3d_device *device, 00906 UINT swapchain_idx, struct wined3d_swapchain **swapchain) 00907 { 00908 TRACE("device %p, swapchain_idx %u, swapchain %p.\n", 00909 device, swapchain_idx, swapchain); 00910 00911 if (swapchain_idx >= device->swapchain_count) 00912 { 00913 WARN("swapchain_idx %u >= swapchain_count %u.\n", 00914 swapchain_idx, device->swapchain_count); 00915 *swapchain = NULL; 00916 00917 return WINED3DERR_INVALIDCALL; 00918 } 00919 00920 *swapchain = device->swapchains[swapchain_idx]; 00921 wined3d_swapchain_incref(*swapchain); 00922 TRACE("Returning %p.\n", *swapchain); 00923 00924 return WINED3D_OK; 00925 } 00926 00927 static void device_load_logo(struct wined3d_device *device, const char *filename) 00928 { 00929 struct wined3d_color_key color_key; 00930 HBITMAP hbm; 00931 BITMAP bm; 00932 HRESULT hr; 00933 HDC dcb = NULL, dcs = NULL; 00934 00935 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); 00936 if(hbm) 00937 { 00938 GetObjectA(hbm, sizeof(BITMAP), &bm); 00939 dcb = CreateCompatibleDC(NULL); 00940 if(!dcb) goto out; 00941 SelectObject(dcb, hbm); 00942 } 00943 else 00944 { 00945 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image 00946 * couldn't be loaded 00947 */ 00948 memset(&bm, 0, sizeof(bm)); 00949 bm.bmWidth = 32; 00950 bm.bmHeight = 32; 00951 } 00952 00953 hr = wined3d_surface_create(device, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, 0, 0, 00954 WINED3D_POOL_DEFAULT, WINED3D_MULTISAMPLE_NONE, 0, SURFACE_OPENGL, WINED3D_SURFACE_MAPPABLE, 00955 NULL, &wined3d_null_parent_ops, &device->logo_surface); 00956 if (FAILED(hr)) 00957 { 00958 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr); 00959 goto out; 00960 } 00961 00962 if (dcb) 00963 { 00964 if (FAILED(hr = wined3d_surface_getdc(device->logo_surface, &dcs))) 00965 goto out; 00966 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY); 00967 wined3d_surface_releasedc(device->logo_surface, dcs); 00968 00969 color_key.color_space_low_value = 0; 00970 color_key.color_space_high_value = 0; 00971 wined3d_surface_set_color_key(device->logo_surface, WINEDDCKEY_SRCBLT, &color_key); 00972 } 00973 else 00974 { 00975 const struct wined3d_color c = {1.0f, 1.0f, 1.0f, 1.0f}; 00976 /* Fill the surface with a white color to show that wined3d is there */ 00977 wined3d_device_color_fill(device, device->logo_surface, NULL, &c); 00978 } 00979 00980 out: 00981 if (dcb) DeleteDC(dcb); 00982 if (hbm) DeleteObject(hbm); 00983 } 00984 00985 /* Context activation is done by the caller. */ 00986 static void create_dummy_textures(struct wined3d_device *device, struct wined3d_context *context) 00987 { 00988 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 00989 unsigned int i, j, count; 00990 /* Under DirectX you can sample even if no texture is bound, whereas 00991 * OpenGL will only allow that when a valid texture is bound. 00992 * We emulate this by creating dummy textures and binding them 00993 * to each texture stage when the currently set D3D texture is NULL. */ 00994 ENTER_GL(); 00995 00996 if (gl_info->supported[APPLE_CLIENT_STORAGE]) 00997 { 00998 /* The dummy texture does not have client storage backing */ 00999 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); 01000 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)"); 01001 } 01002 01003 count = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers); 01004 for (i = 0; i < count; ++i) 01005 { 01006 DWORD color = 0x000000ff; 01007 01008 /* Make appropriate texture active */ 01009 context_active_texture(context, gl_info, i); 01010 01011 glGenTextures(1, &device->dummy_texture_2d[i]); 01012 checkGLcall("glGenTextures"); 01013 TRACE("Dummy 2D texture %u given name %u.\n", i, device->dummy_texture_2d[i]); 01014 01015 glBindTexture(GL_TEXTURE_2D, device->dummy_texture_2d[i]); 01016 checkGLcall("glBindTexture"); 01017 01018 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, &color); 01019 checkGLcall("glTexImage2D"); 01020 01021 if (gl_info->supported[ARB_TEXTURE_RECTANGLE]) 01022 { 01023 glGenTextures(1, &device->dummy_texture_rect[i]); 01024 checkGLcall("glGenTextures"); 01025 TRACE("Dummy rectangle texture %u given name %u.\n", i, device->dummy_texture_rect[i]); 01026 01027 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, device->dummy_texture_rect[i]); 01028 checkGLcall("glBindTexture"); 01029 01030 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, &color); 01031 checkGLcall("glTexImage2D"); 01032 } 01033 01034 if (gl_info->supported[EXT_TEXTURE3D]) 01035 { 01036 glGenTextures(1, &device->dummy_texture_3d[i]); 01037 checkGLcall("glGenTextures"); 01038 TRACE("Dummy 3D texture %u given name %u.\n", i, device->dummy_texture_3d[i]); 01039 01040 glBindTexture(GL_TEXTURE_3D, device->dummy_texture_3d[i]); 01041 checkGLcall("glBindTexture"); 01042 01043 GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D, 0, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, &color)); 01044 checkGLcall("glTexImage3D"); 01045 } 01046 01047 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP]) 01048 { 01049 glGenTextures(1, &device->dummy_texture_cube[i]); 01050 checkGLcall("glGenTextures"); 01051 TRACE("Dummy cube texture %u given name %u.\n", i, device->dummy_texture_cube[i]); 01052 01053 glBindTexture(GL_TEXTURE_CUBE_MAP, device->dummy_texture_cube[i]); 01054 checkGLcall("glBindTexture"); 01055 01056 for (j = GL_TEXTURE_CUBE_MAP_POSITIVE_X; j <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; ++j) 01057 { 01058 glTexImage2D(j, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, &color); 01059 checkGLcall("glTexImage2D"); 01060 } 01061 } 01062 } 01063 01064 if (gl_info->supported[APPLE_CLIENT_STORAGE]) 01065 { 01066 /* Reenable because if supported it is enabled by default */ 01067 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); 01068 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)"); 01069 } 01070 01071 LEAVE_GL(); 01072 } 01073 01074 /* Context activation is done by the caller. */ 01075 static void destroy_dummy_textures(struct wined3d_device *device, const struct wined3d_gl_info *gl_info) 01076 { 01077 unsigned int count = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers); 01078 01079 ENTER_GL(); 01080 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP]) 01081 { 01082 glDeleteTextures(count, device->dummy_texture_cube); 01083 checkGLcall("glDeleteTextures(count, device->dummy_texture_cube)"); 01084 } 01085 01086 if (gl_info->supported[EXT_TEXTURE3D]) 01087 { 01088 glDeleteTextures(count, device->dummy_texture_3d); 01089 checkGLcall("glDeleteTextures(count, device->dummy_texture_3d)"); 01090 } 01091 01092 if (gl_info->supported[ARB_TEXTURE_RECTANGLE]) 01093 { 01094 glDeleteTextures(count, device->dummy_texture_rect); 01095 checkGLcall("glDeleteTextures(count, device->dummy_texture_rect)"); 01096 } 01097 01098 glDeleteTextures(count, device->dummy_texture_2d); 01099 checkGLcall("glDeleteTextures(count, device->dummy_texture_2d)"); 01100 LEAVE_GL(); 01101 01102 memset(device->dummy_texture_cube, 0, gl_info->limits.textures * sizeof(*device->dummy_texture_cube)); 01103 memset(device->dummy_texture_3d, 0, gl_info->limits.textures * sizeof(*device->dummy_texture_3d)); 01104 memset(device->dummy_texture_rect, 0, gl_info->limits.textures * sizeof(*device->dummy_texture_rect)); 01105 memset(device->dummy_texture_2d, 0, gl_info->limits.textures * sizeof(*device->dummy_texture_2d)); 01106 } 01107 01108 static LONG fullscreen_style(LONG style) 01109 { 01110 /* Make sure the window is managed, otherwise we won't get keyboard input. */ 01111 style |= WS_POPUP | WS_SYSMENU; 01112 style &= ~(WS_CAPTION | WS_THICKFRAME); 01113 01114 return style; 01115 } 01116 01117 static LONG fullscreen_exstyle(LONG exstyle) 01118 { 01119 /* Filter out window decorations. */ 01120 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE); 01121 01122 return exstyle; 01123 } 01124 01125 void CDECL wined3d_device_setup_fullscreen_window(struct wined3d_device *device, HWND window, UINT w, UINT h) 01126 { 01127 BOOL filter_messages; 01128 LONG style, exstyle; 01129 01130 TRACE("Setting up window %p for fullscreen mode.\n", window); 01131 01132 if (device->style || device->exStyle) 01133 { 01134 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n", 01135 window, device->style, device->exStyle); 01136 } 01137 01138 device->style = GetWindowLongW(window, GWL_STYLE); 01139 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE); 01140 01141 style = fullscreen_style(device->style); 01142 exstyle = fullscreen_exstyle(device->exStyle); 01143 01144 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n", 01145 device->style, device->exStyle, style, exstyle); 01146 01147 filter_messages = device->filter_messages; 01148 device->filter_messages = TRUE; 01149 01150 SetWindowLongW(window, GWL_STYLE, style); 01151 SetWindowLongW(window, GWL_EXSTYLE, exstyle); 01152 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE); 01153 01154 device->filter_messages = filter_messages; 01155 } 01156 01157 void CDECL wined3d_device_restore_fullscreen_window(struct wined3d_device *device, HWND window) 01158 { 01159 BOOL filter_messages; 01160 LONG style, exstyle; 01161 01162 if (!device->style && !device->exStyle) return; 01163 01164 TRACE("Restoring window style of window %p to %08x, %08x.\n", 01165 window, device->style, device->exStyle); 01166 01167 style = GetWindowLongW(window, GWL_STYLE); 01168 exstyle = GetWindowLongW(window, GWL_EXSTYLE); 01169 01170 filter_messages = device->filter_messages; 01171 device->filter_messages = TRUE; 01172 01173 /* Only restore the style if the application didn't modify it during the 01174 * fullscreen phase. Some applications change it before calling Reset() 01175 * when switching between windowed and fullscreen modes (HL2), some 01176 * depend on the original style (Eve Online). */ 01177 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle)) 01178 { 01179 SetWindowLongW(window, GWL_STYLE, device->style); 01180 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle); 01181 } 01182 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 01183 01184 device->filter_messages = filter_messages; 01185 01186 /* Delete the old values. */ 01187 device->style = 0; 01188 device->exStyle = 0; 01189 } 01190 01191 HRESULT CDECL wined3d_device_acquire_focus_window(struct wined3d_device *device, HWND window) 01192 { 01193 TRACE("device %p, window %p.\n", device, window); 01194 01195 if (!wined3d_register_window(window, device)) 01196 { 01197 ERR("Failed to register window %p.\n", window); 01198 return E_FAIL; 01199 } 01200 01201 device->focus_window = window; 01202 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); 01203 01204 return WINED3D_OK; 01205 } 01206 01207 void CDECL wined3d_device_release_focus_window(struct wined3d_device *device) 01208 { 01209 TRACE("device %p.\n", device); 01210 01211 if (device->focus_window) wined3d_unregister_window(device->focus_window); 01212 device->focus_window = NULL; 01213 } 01214 01215 HRESULT CDECL wined3d_device_init_3d(struct wined3d_device *device, 01216 struct wined3d_swapchain_desc *swapchain_desc) 01217 { 01218 static const struct wined3d_color black = {0.0f, 0.0f, 0.0f, 0.0f}; 01219 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 01220 struct wined3d_swapchain *swapchain = NULL; 01221 struct wined3d_context *context; 01222 HRESULT hr; 01223 DWORD state; 01224 unsigned int i; 01225 01226 TRACE("device %p, swapchain_desc %p.\n", device, swapchain_desc); 01227 01228 if (device->d3d_initialized) 01229 return WINED3DERR_INVALIDCALL; 01230 if (!device->adapter->opengl) 01231 return WINED3DERR_INVALIDCALL; 01232 01233 device->valid_rt_mask = 0; 01234 for (i = 0; i < gl_info->limits.buffers; ++i) 01235 device->valid_rt_mask |= (1 << i); 01236 device->fb.render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 01237 sizeof(*device->fb.render_targets) * gl_info->limits.buffers); 01238 01239 /* Initialize the texture unit mapping to a 1:1 mapping */ 01240 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) 01241 { 01242 if (state < gl_info->limits.fragment_samplers) 01243 { 01244 device->texUnitMap[state] = state; 01245 device->rev_tex_unit_map[state] = state; 01246 } 01247 else 01248 { 01249 device->texUnitMap[state] = WINED3D_UNMAPPED_STAGE; 01250 device->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE; 01251 } 01252 } 01253 01254 /* Setup the implicit swapchain. This also initializes a context. */ 01255 TRACE("Creating implicit swapchain\n"); 01256 hr = device->device_parent->ops->create_swapchain(device->device_parent, 01257 swapchain_desc, &swapchain); 01258 if (FAILED(hr)) 01259 { 01260 WARN("Failed to create implicit swapchain\n"); 01261 goto err_out; 01262 } 01263 01264 device->swapchain_count = 1; 01265 device->swapchains = HeapAlloc(GetProcessHeap(), 0, device->swapchain_count * sizeof(*device->swapchains)); 01266 if (!device->swapchains) 01267 { 01268 ERR("Out of memory!\n"); 01269 goto err_out; 01270 } 01271 device->swapchains[0] = swapchain; 01272 01273 if (swapchain->back_buffers && swapchain->back_buffers[0]) 01274 { 01275 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers); 01276 device->fb.render_targets[0] = swapchain->back_buffers[0]; 01277 } 01278 else 01279 { 01280 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer); 01281 device->fb.render_targets[0] = swapchain->front_buffer; 01282 } 01283 wined3d_surface_incref(device->fb.render_targets[0]); 01284 01285 /* Depth Stencil support */ 01286 device->fb.depth_stencil = device->auto_depth_stencil; 01287 if (device->fb.depth_stencil) 01288 wined3d_surface_incref(device->fb.depth_stencil); 01289 01290 hr = device->shader_backend->shader_alloc_private(device); 01291 if (FAILED(hr)) 01292 { 01293 TRACE("Shader private data couldn't be allocated\n"); 01294 goto err_out; 01295 } 01296 hr = device->frag_pipe->alloc_private(device); 01297 if (FAILED(hr)) 01298 { 01299 TRACE("Fragment pipeline private data couldn't be allocated\n"); 01300 goto err_out; 01301 } 01302 hr = device->blitter->alloc_private(device); 01303 if (FAILED(hr)) 01304 { 01305 TRACE("Blitter private data couldn't be allocated\n"); 01306 goto err_out; 01307 } 01308 01309 /* Set up some starting GL setup */ 01310 01311 /* Setup all the devices defaults */ 01312 stateblock_init_default_state(device->stateBlock); 01313 01314 context = context_acquire(device, swapchain->front_buffer); 01315 01316 create_dummy_textures(device, context); 01317 01318 ENTER_GL(); 01319 01320 /* Initialize the current view state */ 01321 device->view_ident = 1; 01322 device->contexts[0]->last_was_rhw = 0; 01323 01324 switch (wined3d_settings.offscreen_rendering_mode) 01325 { 01326 case ORM_FBO: 01327 device->offscreenBuffer = GL_COLOR_ATTACHMENT0; 01328 break; 01329 01330 case ORM_BACKBUFFER: 01331 { 01332 if (context_get_current()->aux_buffers > 0) 01333 { 01334 TRACE("Using auxiliary buffer for offscreen rendering\n"); 01335 device->offscreenBuffer = GL_AUX0; 01336 } 01337 else 01338 { 01339 TRACE("Using back buffer for offscreen rendering\n"); 01340 device->offscreenBuffer = GL_BACK; 01341 } 01342 } 01343 } 01344 01345 TRACE("All defaults now set up, leaving 3D init.\n"); 01346 LEAVE_GL(); 01347 01348 context_release(context); 01349 01350 /* Clear the screen */ 01351 wined3d_device_clear(device, 0, NULL, WINED3DCLEAR_TARGET 01352 | (swapchain_desc->enable_auto_depth_stencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0), 01353 &black, 1.0f, 0); 01354 01355 device->d3d_initialized = TRUE; 01356 01357 if (wined3d_settings.logo) 01358 device_load_logo(device, wined3d_settings.logo); 01359 return WINED3D_OK; 01360 01361 err_out: 01362 HeapFree(GetProcessHeap(), 0, device->fb.render_targets); 01363 HeapFree(GetProcessHeap(), 0, device->swapchains); 01364 device->swapchain_count = 0; 01365 if (swapchain) 01366 wined3d_swapchain_decref(swapchain); 01367 if (device->blit_priv) 01368 device->blitter->free_private(device); 01369 if (device->fragment_priv) 01370 device->frag_pipe->free_private(device); 01371 if (device->shader_priv) 01372 device->shader_backend->shader_free_private(device); 01373 01374 return hr; 01375 } 01376 01377 HRESULT CDECL wined3d_device_init_gdi(struct wined3d_device *device, 01378 struct wined3d_swapchain_desc *swapchain_desc) 01379 { 01380 struct wined3d_swapchain *swapchain = NULL; 01381 HRESULT hr; 01382 01383 TRACE("device %p, swapchain_desc %p.\n", device, swapchain_desc); 01384 01385 /* Setup the implicit swapchain */ 01386 TRACE("Creating implicit swapchain\n"); 01387 hr = device->device_parent->ops->create_swapchain(device->device_parent, 01388 swapchain_desc, &swapchain); 01389 if (FAILED(hr)) 01390 { 01391 WARN("Failed to create implicit swapchain\n"); 01392 goto err_out; 01393 } 01394 01395 device->swapchain_count = 1; 01396 device->swapchains = HeapAlloc(GetProcessHeap(), 0, device->swapchain_count * sizeof(*device->swapchains)); 01397 if (!device->swapchains) 01398 { 01399 ERR("Out of memory!\n"); 01400 goto err_out; 01401 } 01402 device->swapchains[0] = swapchain; 01403 return WINED3D_OK; 01404 01405 err_out: 01406 wined3d_swapchain_decref(swapchain); 01407 return hr; 01408 } 01409 01410 HRESULT CDECL wined3d_device_uninit_3d(struct wined3d_device *device) 01411 { 01412 struct wined3d_resource *resource, *cursor; 01413 const struct wined3d_gl_info *gl_info; 01414 struct wined3d_context *context; 01415 struct wined3d_surface *surface; 01416 UINT i; 01417 01418 TRACE("device %p.\n", device); 01419 01420 if (!device->d3d_initialized) 01421 return WINED3DERR_INVALIDCALL; 01422 01423 /* Force making the context current again, to verify it is still valid 01424 * (workaround for broken drivers) */ 01425 context_set_current(NULL); 01426 /* I don't think that the interface guarantees that the device is destroyed from the same thread 01427 * it was created. Thus make sure a context is active for the glDelete* calls 01428 */ 01429 context = context_acquire(device, NULL); 01430 gl_info = context->gl_info; 01431 01432 if (device->logo_surface) 01433 wined3d_surface_decref(device->logo_surface); 01434 01435 stateblock_unbind_resources(device->stateBlock); 01436 01437 /* Unload resources */ 01438 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry) 01439 { 01440 TRACE("Unloading resource %p.\n", resource); 01441 01442 resource->resource_ops->resource_unload(resource); 01443 } 01444 01445 TRACE("Deleting high order patches\n"); 01446 for(i = 0; i < PATCHMAP_SIZE; i++) { 01447 struct list *e1, *e2; 01448 struct WineD3DRectPatch *patch; 01449 LIST_FOR_EACH_SAFE(e1, e2, &device->patches[i]) 01450 { 01451 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry); 01452 wined3d_device_delete_patch(device, patch->Handle); 01453 } 01454 } 01455 01456 /* Delete the mouse cursor texture */ 01457 if (device->cursorTexture) 01458 { 01459 ENTER_GL(); 01460 glDeleteTextures(1, &device->cursorTexture); 01461 LEAVE_GL(); 01462 device->cursorTexture = 0; 01463 } 01464 01465 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader 01466 * private data, it might contain opengl pointers 01467 */ 01468 if (device->depth_blt_texture) 01469 { 01470 ENTER_GL(); 01471 glDeleteTextures(1, &device->depth_blt_texture); 01472 LEAVE_GL(); 01473 device->depth_blt_texture = 0; 01474 } 01475 01476 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */ 01477 device->blitter->free_private(device); 01478 device->frag_pipe->free_private(device); 01479 device->shader_backend->shader_free_private(device); 01480 01481 /* Release the buffers (with sanity checks)*/ 01482 if (device->onscreen_depth_stencil) 01483 { 01484 surface = device->onscreen_depth_stencil; 01485 device->onscreen_depth_stencil = NULL; 01486 wined3d_surface_decref(surface); 01487 } 01488 01489 if (device->fb.depth_stencil) 01490 { 01491 surface = device->fb.depth_stencil; 01492 01493 TRACE("Releasing depth/stencil buffer %p.\n", surface); 01494 01495 device->fb.depth_stencil = NULL; 01496 wined3d_surface_decref(surface); 01497 } 01498 01499 if (device->auto_depth_stencil) 01500 { 01501 surface = device->auto_depth_stencil; 01502 device->auto_depth_stencil = NULL; 01503 if (wined3d_surface_decref(surface)) 01504 FIXME("Something's still holding the auto depth stencil buffer (%p).\n", surface); 01505 } 01506 01507 for (i = 1; i < gl_info->limits.buffers; ++i) 01508 { 01509 wined3d_device_set_render_target(device, i, NULL, FALSE); 01510 } 01511 01512 surface = device->fb.render_targets[0]; 01513 TRACE("Setting rendertarget 0 to NULL\n"); 01514 device->fb.render_targets[0] = NULL; 01515 TRACE("Releasing the render target at %p\n", surface); 01516 wined3d_surface_decref(surface); 01517 01518 context_release(context); 01519 01520 for (i = 0; i < device->swapchain_count; ++i) 01521 { 01522 TRACE("Releasing the implicit swapchain %u.\n", i); 01523 if (wined3d_swapchain_decref(device->swapchains[i])) 01524 FIXME("Something's still holding the implicit swapchain.\n"); 01525 } 01526 01527 HeapFree(GetProcessHeap(), 0, device->swapchains); 01528 device->swapchains = NULL; 01529 device->swapchain_count = 0; 01530 01531 HeapFree(GetProcessHeap(), 0, device->fb.render_targets); 01532 device->fb.render_targets = NULL; 01533 01534 device->d3d_initialized = FALSE; 01535 01536 return WINED3D_OK; 01537 } 01538 01539 HRESULT CDECL wined3d_device_uninit_gdi(struct wined3d_device *device) 01540 { 01541 unsigned int i; 01542 01543 for (i = 0; i < device->swapchain_count; ++i) 01544 { 01545 TRACE("Releasing the implicit swapchain %u.\n", i); 01546 if (wined3d_swapchain_decref(device->swapchains[i])) 01547 FIXME("Something's still holding the implicit swapchain.\n"); 01548 } 01549 01550 HeapFree(GetProcessHeap(), 0, device->swapchains); 01551 device->swapchains = NULL; 01552 device->swapchain_count = 0; 01553 return WINED3D_OK; 01554 } 01555 01556 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw 01557 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from 01558 * CreateDevice if D3DCREATE_MULTITHREADED is passed. 01559 * 01560 * There is no way to deactivate thread safety once it is enabled. 01561 */ 01562 void CDECL wined3d_device_set_multithreaded(struct wined3d_device *device) 01563 { 01564 TRACE("device %p.\n", device); 01565 01566 /* For now just store the flag (needed in case of ddraw). */ 01567 device->create_parms.flags |= WINED3DCREATE_MULTITHREADED; 01568 } 01569 01570 HRESULT CDECL wined3d_device_set_display_mode(struct wined3d_device *device, 01571 UINT swapchain_idx, const struct wined3d_display_mode *mode) 01572 { 01573 struct wined3d_adapter *adapter = device->adapter; 01574 const struct wined3d_format *format = wined3d_get_format(&adapter->gl_info, mode->format_id); 01575 DEVMODEW devmode; 01576 LONG ret; 01577 RECT clip_rc; 01578 01579 TRACE("device %p, swapchain_idx %u, mode %p (%ux%u@%u %s).\n", device, swapchain_idx, mode, 01580 mode->width, mode->height, mode->refresh_rate, debug_d3dformat(mode->format_id)); 01581 01582 /* Resize the screen even without a window: 01583 * The app could have unset it with SetCooperativeLevel, but not called 01584 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode, 01585 * but we don't have any hwnd 01586 */ 01587 01588 memset(&devmode, 0, sizeof(devmode)); 01589 devmode.dmSize = sizeof(devmode); 01590 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; 01591 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT; 01592 devmode.dmPelsWidth = mode->width; 01593 devmode.dmPelsHeight = mode->height; 01594 01595 devmode.dmDisplayFrequency = mode->refresh_rate; 01596 if (mode->refresh_rate) 01597 devmode.dmFields |= DM_DISPLAYFREQUENCY; 01598 01599 /* Only change the mode if necessary */ 01600 if (adapter->screen_size.cx == mode->width && adapter->screen_size.cy == mode->height 01601 && adapter->screen_format == mode->format_id && !mode->refresh_rate) 01602 return WINED3D_OK; 01603 01604 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL); 01605 if (ret != DISP_CHANGE_SUCCESSFUL) 01606 { 01607 if (devmode.dmDisplayFrequency) 01608 { 01609 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n"); 01610 devmode.dmFields &= ~DM_DISPLAYFREQUENCY; 01611 devmode.dmDisplayFrequency = 0; 01612 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL; 01613 } 01614 if(ret != DISP_CHANGE_SUCCESSFUL) { 01615 return WINED3DERR_NOTAVAILABLE; 01616 } 01617 } 01618 01619 /* Store the new values */ 01620 adapter->screen_size.cx = mode->width; 01621 adapter->screen_size.cy = mode->height; 01622 adapter->screen_format = mode->format_id; 01623 01624 /* And finally clip mouse to our screen */ 01625 SetRect(&clip_rc, 0, 0, mode->width, mode->height); 01626 ClipCursor(&clip_rc); 01627 01628 return WINED3D_OK; 01629 } 01630 01631 HRESULT CDECL wined3d_device_get_wined3d(const struct wined3d_device *device, struct wined3d **wined3d) 01632 { 01633 TRACE("device %p, wined3d %p.\n", device, wined3d); 01634 01635 *wined3d = device->wined3d; 01636 wined3d_incref(*wined3d); 01637 01638 TRACE("Returning %p.\n", *wined3d); 01639 01640 return WINED3D_OK; 01641 } 01642 01643 UINT CDECL wined3d_device_get_available_texture_mem(const struct wined3d_device *device) 01644 { 01645 TRACE("device %p.\n", device); 01646 01647 TRACE("Emulating %d MB, returning %d MB left.\n", 01648 device->adapter->TextureRam / (1024 * 1024), 01649 (device->adapter->TextureRam - device->adapter->UsedTextureRam) / (1024 * 1024)); 01650 01651 return device->adapter->TextureRam - device->adapter->UsedTextureRam; 01652 } 01653 01654 HRESULT CDECL wined3d_device_set_stream_source(struct wined3d_device *device, UINT stream_idx, 01655 struct wined3d_buffer *buffer, UINT offset, UINT stride) 01656 { 01657 struct wined3d_stream_state *stream; 01658 struct wined3d_buffer *prev_buffer; 01659 01660 TRACE("device %p, stream_idx %u, buffer %p, offset %u, stride %u.\n", 01661 device, stream_idx, buffer, offset, stride); 01662 01663 if (stream_idx >= MAX_STREAMS) 01664 { 01665 WARN("Stream index %u out of range.\n", stream_idx); 01666 return WINED3DERR_INVALIDCALL; 01667 } 01668 else if (offset & 0x3) 01669 { 01670 WARN("Offset %u is not 4 byte aligned.\n", offset); 01671 return WINED3DERR_INVALIDCALL; 01672 } 01673 01674 stream = &device->updateStateBlock->state.streams[stream_idx]; 01675 prev_buffer = stream->buffer; 01676 01677 device->updateStateBlock->changed.streamSource |= 1 << stream_idx; 01678 01679 if (prev_buffer == buffer 01680 && stream->stride == stride 01681 && stream->offset == offset) 01682 { 01683 TRACE("Application is setting the old values over, nothing to do.\n"); 01684 return WINED3D_OK; 01685 } 01686 01687 stream->buffer = buffer; 01688 if (buffer) 01689 { 01690 stream->stride = stride; 01691 stream->offset = offset; 01692 } 01693 01694 /* Handle recording of state blocks. */ 01695 if (device->isRecordingState) 01696 { 01697 TRACE("Recording... not performing anything.\n"); 01698 if (buffer) 01699 wined3d_buffer_incref(buffer); 01700 if (prev_buffer) 01701 wined3d_buffer_decref(prev_buffer); 01702 return WINED3D_OK; 01703 } 01704 01705 if (buffer) 01706 { 01707 InterlockedIncrement(&buffer->bind_count); 01708 wined3d_buffer_incref(buffer); 01709 } 01710 if (prev_buffer) 01711 { 01712 InterlockedDecrement(&prev_buffer->bind_count); 01713 wined3d_buffer_decref(prev_buffer); 01714 } 01715 01716 device_invalidate_state(device, STATE_STREAMSRC); 01717 01718 return WINED3D_OK; 01719 } 01720 01721 HRESULT CDECL wined3d_device_get_stream_source(const struct wined3d_device *device, 01722 UINT stream_idx, struct wined3d_buffer **buffer, UINT *offset, UINT *stride) 01723 { 01724 struct wined3d_stream_state *stream; 01725 01726 TRACE("device %p, stream_idx %u, buffer %p, offset %p, stride %p.\n", 01727 device, stream_idx, buffer, offset, stride); 01728 01729 if (stream_idx >= MAX_STREAMS) 01730 { 01731 WARN("Stream index %u out of range.\n", stream_idx); 01732 return WINED3DERR_INVALIDCALL; 01733 } 01734 01735 stream = &device->stateBlock->state.streams[stream_idx]; 01736 *buffer = stream->buffer; 01737 if (*buffer) 01738 wined3d_buffer_incref(*buffer); 01739 if (offset) 01740 *offset = stream->offset; 01741 *stride = stream->stride; 01742 01743 return WINED3D_OK; 01744 } 01745 01746 HRESULT CDECL wined3d_device_set_stream_source_freq(struct wined3d_device *device, UINT stream_idx, UINT divider) 01747 { 01748 struct wined3d_stream_state *stream; 01749 UINT old_flags, old_freq; 01750 01751 TRACE("device %p, stream_idx %u, divider %#x.\n", device, stream_idx, divider); 01752 01753 /* Verify input. At least in d3d9 this is invalid. */ 01754 if ((divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (divider & WINED3DSTREAMSOURCE_INDEXEDDATA)) 01755 { 01756 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL.\n"); 01757 return WINED3DERR_INVALIDCALL; 01758 } 01759 if ((divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !stream_idx) 01760 { 01761 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL.\n"); 01762 return WINED3DERR_INVALIDCALL; 01763 } 01764 if (!divider) 01765 { 01766 WARN("Divider is 0, returning D3DERR_INVALIDCALL.\n"); 01767 return WINED3DERR_INVALIDCALL; 01768 } 01769 01770 stream = &device->updateStateBlock->state.streams[stream_idx]; 01771 old_flags = stream->flags; 01772 old_freq = stream->frequency; 01773 01774 stream->flags = divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA); 01775 stream->frequency = divider & 0x7fffff; 01776 01777 device->updateStateBlock->changed.streamFreq |= 1 << stream_idx; 01778 01779 if (stream->frequency != old_freq || stream->flags != old_flags) 01780 device_invalidate_state(device, STATE_STREAMSRC); 01781 01782 return WINED3D_OK; 01783 } 01784 01785 HRESULT CDECL wined3d_device_get_stream_source_freq(const struct wined3d_device *device, 01786 UINT stream_idx, UINT *divider) 01787 { 01788 struct wined3d_stream_state *stream; 01789 01790 TRACE("device %p, stream_idx %u, divider %p.\n", device, stream_idx, divider); 01791 01792 stream = &device->updateStateBlock->state.streams[stream_idx]; 01793 *divider = stream->flags | stream->frequency; 01794 01795 TRACE("Returning %#x.\n", *divider); 01796 01797 return WINED3D_OK; 01798 } 01799 01800 HRESULT CDECL wined3d_device_set_transform(struct wined3d_device *device, 01801 enum wined3d_transform_state d3dts, const struct wined3d_matrix *matrix) 01802 { 01803 TRACE("device %p, state %s, matrix %p.\n", 01804 device, debug_d3dtstype(d3dts), matrix); 01805 01806 /* Handle recording of state blocks. */ 01807 if (device->isRecordingState) 01808 { 01809 TRACE("Recording... not performing anything.\n"); 01810 device->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f); 01811 device->updateStateBlock->state.transforms[d3dts] = *matrix; 01812 return WINED3D_OK; 01813 } 01814 01815 /* If the new matrix is the same as the current one, 01816 * we cut off any further processing. this seems to be a reasonable 01817 * optimization because as was noticed, some apps (warcraft3 for example) 01818 * tend towards setting the same matrix repeatedly for some reason. 01819 * 01820 * From here on we assume that the new matrix is different, wherever it matters. */ 01821 if (!memcmp(&device->stateBlock->state.transforms[d3dts].u.m[0][0], matrix, sizeof(*matrix))) 01822 { 01823 TRACE("The application is setting the same matrix over again.\n"); 01824 return WINED3D_OK; 01825 } 01826 01827 conv_mat(matrix, &device->stateBlock->state.transforms[d3dts].u.m[0][0]); 01828 01829 /* ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord 01830 * where ViewMat = Camera space, WorldMat = world space. 01831 * 01832 * In OpenGL, camera and world space is combined into GL_MODELVIEW 01833 * matrix. The Projection matrix stay projection matrix. */ 01834 01835 if (d3dts == WINED3D_TS_VIEW) 01836 device->view_ident = !memcmp(matrix, identity, 16 * sizeof(float)); 01837 01838 if (d3dts < WINED3D_TS_WORLD_MATRIX(device->adapter->gl_info.limits.blends)) 01839 device_invalidate_state(device, STATE_TRANSFORM(d3dts)); 01840 01841 return WINED3D_OK; 01842 01843 } 01844 01845 HRESULT CDECL wined3d_device_get_transform(const struct wined3d_device *device, 01846 enum wined3d_transform_state state, struct wined3d_matrix *matrix) 01847 { 01848 TRACE("device %p, state %s, matrix %p.\n", device, debug_d3dtstype(state), matrix); 01849 01850 *matrix = device->stateBlock->state.transforms[state]; 01851 01852 return WINED3D_OK; 01853 } 01854 01855 HRESULT CDECL wined3d_device_multiply_transform(struct wined3d_device *device, 01856 enum wined3d_transform_state state, const struct wined3d_matrix *matrix) 01857 { 01858 const struct wined3d_matrix *mat = NULL; 01859 struct wined3d_matrix temp; 01860 01861 TRACE("device %p, state %s, matrix %p.\n", device, debug_d3dtstype(state), matrix); 01862 01863 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code 01864 * below means it will be recorded in a state block change, but it 01865 * works regardless where it is recorded. 01866 * If this is found to be wrong, change to StateBlock. */ 01867 if (state > HIGHEST_TRANSFORMSTATE) 01868 { 01869 WARN("Unhandled transform state %#x.\n", state); 01870 return WINED3D_OK; 01871 } 01872 01873 mat = &device->updateStateBlock->state.transforms[state]; 01874 multiply_matrix(&temp, mat, matrix); 01875 01876 /* Apply change via set transform - will reapply to eg. lights this way. */ 01877 return wined3d_device_set_transform(device, state, &temp); 01878 } 01879 01880 /* Note lights are real special cases. Although the device caps state only 01881 * e.g. 8 are supported, you can reference any indexes you want as long as 01882 * that number max are enabled at any one point in time. Therefore since the 01883 * indices can be anything, we need a hashmap of them. However, this causes 01884 * stateblock problems. When capturing the state block, I duplicate the 01885 * hashmap, but when recording, just build a chain pretty much of commands to 01886 * be replayed. */ 01887 HRESULT CDECL wined3d_device_set_light(struct wined3d_device *device, 01888 UINT light_idx, const struct wined3d_light *light) 01889 { 01890 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx); 01891 struct wined3d_light_info *object = NULL; 01892 struct list *e; 01893 float rho; 01894 01895 TRACE("device %p, light_idx %u, light %p.\n", device, light_idx, light); 01896 01897 /* Check the parameter range. Need for speed most wanted sets junk lights 01898 * which confuse the GL driver. */ 01899 if (!light) 01900 return WINED3DERR_INVALIDCALL; 01901 01902 switch (light->type) 01903 { 01904 case WINED3D_LIGHT_POINT: 01905 case WINED3D_LIGHT_SPOT: 01906 case WINED3D_LIGHT_PARALLELPOINT: 01907 case WINED3D_LIGHT_GLSPOT: 01908 /* Incorrect attenuation values can cause the gl driver to crash. 01909 * Happens with Need for speed most wanted. */ 01910 if (light->attenuation0 < 0.0f || light->attenuation1 < 0.0f || light->attenuation2 < 0.0f) 01911 { 01912 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL.\n"); 01913 return WINED3DERR_INVALIDCALL; 01914 } 01915 break; 01916 01917 case WINED3D_LIGHT_DIRECTIONAL: 01918 /* Ignores attenuation */ 01919 break; 01920 01921 default: 01922 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n"); 01923 return WINED3DERR_INVALIDCALL; 01924 } 01925 01926 LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx]) 01927 { 01928 object = LIST_ENTRY(e, struct wined3d_light_info, entry); 01929 if (object->OriginalIndex == light_idx) 01930 break; 01931 object = NULL; 01932 } 01933 01934 if (!object) 01935 { 01936 TRACE("Adding new light\n"); 01937 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); 01938 if (!object) 01939 { 01940 ERR("Out of memory error when allocating a light\n"); 01941 return E_OUTOFMEMORY; 01942 } 01943 list_add_head(&device->updateStateBlock->state.light_map[hash_idx], &object->entry); 01944 object->glIndex = -1; 01945 object->OriginalIndex = light_idx; 01946 } 01947 01948 /* Initialize the object. */ 01949 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", 01950 light_idx, light->type, 01951 light->diffuse.r, light->diffuse.g, light->diffuse.b, light->diffuse.a, 01952 light->specular.r, light->specular.g, light->specular.b, light->specular.a, 01953 light->ambient.r, light->ambient.g, light->ambient.b, light->ambient.a); 01954 TRACE("... Pos(%f,%f,%f), Dir(%f,%f,%f)\n", light->position.x, light->position.y, light->position.z, 01955 light->direction.x, light->direction.y, light->direction.z); 01956 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", 01957 light->range, light->falloff, light->theta, light->phi); 01958 01959 /* Save away the information. */ 01960 object->OriginalParms = *light; 01961 01962 switch (light->type) 01963 { 01964 case WINED3D_LIGHT_POINT: 01965 /* Position */ 01966 object->lightPosn[0] = light->position.x; 01967 object->lightPosn[1] = light->position.y; 01968 object->lightPosn[2] = light->position.z; 01969 object->lightPosn[3] = 1.0f; 01970 object->cutoff = 180.0f; 01971 /* FIXME: Range */ 01972 break; 01973 01974 case WINED3D_LIGHT_DIRECTIONAL: 01975 /* Direction */ 01976 object->lightPosn[0] = -light->direction.x; 01977 object->lightPosn[1] = -light->direction.y; 01978 object->lightPosn[2] = -light->direction.z; 01979 object->lightPosn[3] = 0.0f; 01980 object->exponent = 0.0f; 01981 object->cutoff = 180.0f; 01982 break; 01983 01984 case WINED3D_LIGHT_SPOT: 01985 /* Position */ 01986 object->lightPosn[0] = light->position.x; 01987 object->lightPosn[1] = light->position.y; 01988 object->lightPosn[2] = light->position.z; 01989 object->lightPosn[3] = 1.0f; 01990 01991 /* Direction */ 01992 object->lightDirn[0] = light->direction.x; 01993 object->lightDirn[1] = light->direction.y; 01994 object->lightDirn[2] = light->direction.z; 01995 object->lightDirn[3] = 1.0f; 01996 01997 /* opengl-ish and d3d-ish spot lights use too different models 01998 * for the light "intensity" as a function of the angle towards 01999 * the main light direction, so we only can approximate very 02000 * roughly. However, spot lights are rather rarely used in games 02001 * (if ever used at all). Furthermore if still used, probably 02002 * nobody pays attention to such details. */ 02003 if (!light->falloff) 02004 { 02005 /* Falloff = 0 is easy, because d3d's and opengl's spot light 02006 * equations have the falloff resp. exponent parameter as an 02007 * exponent, so the spot light lighting will always be 1.0 for 02008 * both of them, and we don't have to care for the rest of the 02009 * rather complex calculation. */ 02010 object->exponent = 0.0f; 02011 } 02012 else 02013 { 02014 rho = light->theta + (light->phi - light->theta) / (2 * light->falloff); 02015 if (rho < 0.0001f) 02016 rho = 0.0001f; 02017 object->exponent = -0.3f / logf(cosf(rho / 2)); 02018 } 02019 02020 if (object->exponent > 128.0f) 02021 object->exponent = 128.0f; 02022 02023 object->cutoff = (float)(light->phi * 90 / M_PI); 02024 /* FIXME: Range */ 02025 break; 02026 02027 default: 02028 FIXME("Unrecognized light type %#x.\n", light->type); 02029 } 02030 02031 /* Update the live definitions if the light is currently assigned a glIndex. */ 02032 if (object->glIndex != -1 && !device->isRecordingState) 02033 device_invalidate_state(device, STATE_ACTIVELIGHT(object->glIndex)); 02034 02035 return WINED3D_OK; 02036 } 02037 02038 HRESULT CDECL wined3d_device_get_light(const struct wined3d_device *device, 02039 UINT light_idx, struct wined3d_light *light) 02040 { 02041 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx); 02042 struct wined3d_light_info *light_info = NULL; 02043 struct list *e; 02044 02045 TRACE("device %p, light_idx %u, light %p.\n", device, light_idx, light); 02046 02047 LIST_FOR_EACH(e, &device->stateBlock->state.light_map[hash_idx]) 02048 { 02049 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry); 02050 if (light_info->OriginalIndex == light_idx) 02051 break; 02052 light_info = NULL; 02053 } 02054 02055 if (!light_info) 02056 { 02057 TRACE("Light information requested but light not defined\n"); 02058 return WINED3DERR_INVALIDCALL; 02059 } 02060 02061 *light = light_info->OriginalParms; 02062 return WINED3D_OK; 02063 } 02064 02065 HRESULT CDECL wined3d_device_set_light_enable(struct wined3d_device *device, UINT light_idx, BOOL enable) 02066 { 02067 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx); 02068 struct wined3d_light_info *light_info = NULL; 02069 struct list *e; 02070 02071 TRACE("device %p, light_idx %u, enable %#x.\n", device, light_idx, enable); 02072 02073 LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx]) 02074 { 02075 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry); 02076 if (light_info->OriginalIndex == light_idx) 02077 break; 02078 light_info = NULL; 02079 } 02080 TRACE("Found light %p.\n", light_info); 02081 02082 /* Special case - enabling an undefined light creates one with a strict set of parameters. */ 02083 if (!light_info) 02084 { 02085 TRACE("Light enabled requested but light not defined, so defining one!\n"); 02086 wined3d_device_set_light(device, light_idx, &WINED3D_default_light); 02087 02088 /* Search for it again! Should be fairly quick as near head of list. */ 02089 LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx]) 02090 { 02091 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry); 02092 if (light_info->OriginalIndex == light_idx) 02093 break; 02094 light_info = NULL; 02095 } 02096 if (!light_info) 02097 { 02098 FIXME("Adding default lights has failed dismally\n"); 02099 return WINED3DERR_INVALIDCALL; 02100 } 02101 } 02102 02103 if (!enable) 02104 { 02105 if (light_info->glIndex != -1) 02106 { 02107 if (!device->isRecordingState) 02108 device_invalidate_state(device, STATE_ACTIVELIGHT(light_info->glIndex)); 02109 02110 device->updateStateBlock->state.lights[light_info->glIndex] = NULL; 02111 light_info->glIndex = -1; 02112 } 02113 else 02114 { 02115 TRACE("Light already disabled, nothing to do\n"); 02116 } 02117 light_info->enabled = FALSE; 02118 } 02119 else 02120 { 02121 light_info->enabled = TRUE; 02122 if (light_info->glIndex != -1) 02123 { 02124 TRACE("Nothing to do as light was enabled\n"); 02125 } 02126 else 02127 { 02128 unsigned int i; 02129 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 02130 /* Find a free GL light. */ 02131 for (i = 0; i < gl_info->limits.lights; ++i) 02132 { 02133 if (!device->updateStateBlock->state.lights[i]) 02134 { 02135 device->updateStateBlock->state.lights[i] = light_info; 02136 light_info->glIndex = i; 02137 break; 02138 } 02139 } 02140 if (light_info->glIndex == -1) 02141 { 02142 /* Our tests show that Windows returns D3D_OK in this situation, even with 02143 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This 02144 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE 02145 * as well for those lights. 02146 * 02147 * TODO: Test how this affects rendering. */ 02148 WARN("Too many concurrently active lights\n"); 02149 return WINED3D_OK; 02150 } 02151 02152 /* i == light_info->glIndex */ 02153 if (!device->isRecordingState) 02154 device_invalidate_state(device, STATE_ACTIVELIGHT(i)); 02155 } 02156 } 02157 02158 return WINED3D_OK; 02159 } 02160 02161 HRESULT CDECL wined3d_device_get_light_enable(const struct wined3d_device *device, UINT light_idx, BOOL *enable) 02162 { 02163 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx); 02164 struct wined3d_light_info *light_info = NULL; 02165 struct list *e; 02166 02167 TRACE("device %p, light_idx %u, enable %p.\n", device, light_idx, enable); 02168 02169 LIST_FOR_EACH(e, &device->stateBlock->state.light_map[hash_idx]) 02170 { 02171 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry); 02172 if (light_info->OriginalIndex == light_idx) 02173 break; 02174 light_info = NULL; 02175 } 02176 02177 if (!light_info) 02178 { 02179 TRACE("Light enabled state requested but light not defined.\n"); 02180 return WINED3DERR_INVALIDCALL; 02181 } 02182 /* true is 128 according to SetLightEnable */ 02183 *enable = light_info->enabled ? 128 : 0; 02184 return WINED3D_OK; 02185 } 02186 02187 HRESULT CDECL wined3d_device_set_clip_plane(struct wined3d_device *device, UINT plane_idx, const float *plane) 02188 { 02189 TRACE("device %p, plane_idx %u, plane %p.\n", device, plane_idx, plane); 02190 02191 /* Validate plane_idx. */ 02192 if (plane_idx >= device->adapter->gl_info.limits.clipplanes) 02193 { 02194 TRACE("Application has requested clipplane this device doesn't support.\n"); 02195 return WINED3DERR_INVALIDCALL; 02196 } 02197 02198 device->updateStateBlock->changed.clipplane |= 1 << plane_idx; 02199 02200 if (device->updateStateBlock->state.clip_planes[plane_idx][0] == plane[0] 02201 && device->updateStateBlock->state.clip_planes[plane_idx][1] == plane[1] 02202 && device->updateStateBlock->state.clip_planes[plane_idx][2] == plane[2] 02203 && device->updateStateBlock->state.clip_planes[plane_idx][3] == plane[3]) 02204 { 02205 TRACE("Application is setting old values over, nothing to do.\n"); 02206 return WINED3D_OK; 02207 } 02208 02209 device->updateStateBlock->state.clip_planes[plane_idx][0] = plane[0]; 02210 device->updateStateBlock->state.clip_planes[plane_idx][1] = plane[1]; 02211 device->updateStateBlock->state.clip_planes[plane_idx][2] = plane[2]; 02212 device->updateStateBlock->state.clip_planes[plane_idx][3] = plane[3]; 02213 02214 /* Handle recording of state blocks. */ 02215 if (device->isRecordingState) 02216 { 02217 TRACE("Recording... not performing anything.\n"); 02218 return WINED3D_OK; 02219 } 02220 02221 device_invalidate_state(device, STATE_CLIPPLANE(plane_idx)); 02222 02223 return WINED3D_OK; 02224 } 02225 02226 HRESULT CDECL wined3d_device_get_clip_plane(const struct wined3d_device *device, UINT plane_idx, float *plane) 02227 { 02228 TRACE("device %p, plane_idx %u, plane %p.\n", device, plane_idx, plane); 02229 02230 /* Validate plane_idx. */ 02231 if (plane_idx >= device->adapter->gl_info.limits.clipplanes) 02232 { 02233 TRACE("Application has requested clipplane this device doesn't support.\n"); 02234 return WINED3DERR_INVALIDCALL; 02235 } 02236 02237 plane[0] = (float)device->stateBlock->state.clip_planes[plane_idx][0]; 02238 plane[1] = (float)device->stateBlock->state.clip_planes[plane_idx][1]; 02239 plane[2] = (float)device->stateBlock->state.clip_planes[plane_idx][2]; 02240 plane[3] = (float)device->stateBlock->state.clip_planes[plane_idx][3]; 02241 02242 return WINED3D_OK; 02243 } 02244 02245 HRESULT CDECL wined3d_device_set_clip_status(struct wined3d_device *device, 02246 const struct wined3d_clip_status *clip_status) 02247 { 02248 FIXME("device %p, clip_status %p stub!\n", device, clip_status); 02249 02250 if (!clip_status) 02251 return WINED3DERR_INVALIDCALL; 02252 02253 return WINED3D_OK; 02254 } 02255 02256 HRESULT CDECL wined3d_device_get_clip_status(const struct wined3d_device *device, 02257 struct wined3d_clip_status *clip_status) 02258 { 02259 FIXME("device %p, clip_status %p stub!\n", device, clip_status); 02260 02261 if (!clip_status) 02262 return WINED3DERR_INVALIDCALL; 02263 02264 return WINED3D_OK; 02265 } 02266 02267 HRESULT CDECL wined3d_device_set_material(struct wined3d_device *device, const struct wined3d_material *material) 02268 { 02269 TRACE("device %p, material %p.\n", device, material); 02270 02271 device->updateStateBlock->changed.material = TRUE; 02272 device->updateStateBlock->state.material = *material; 02273 02274 /* Handle recording of state blocks */ 02275 if (device->isRecordingState) 02276 { 02277 TRACE("Recording... not performing anything.\n"); 02278 return WINED3D_OK; 02279 } 02280 02281 device_invalidate_state(device, STATE_MATERIAL); 02282 02283 return WINED3D_OK; 02284 } 02285 02286 HRESULT CDECL wined3d_device_get_material(const struct wined3d_device *device, struct wined3d_material *material) 02287 { 02288 TRACE("device %p, material %p.\n", device, material); 02289 02290 *material = device->updateStateBlock->state.material; 02291 02292 TRACE("diffuse {%.8e, %.8e, %.8e, %.8e}\n", 02293 material->diffuse.r, material->diffuse.g, 02294 material->diffuse.b, material->diffuse.a); 02295 TRACE("ambient {%.8e, %.8e, %.8e, %.8e}\n", 02296 material->ambient.r, material->ambient.g, 02297 material->ambient.b, material->ambient.a); 02298 TRACE("specular {%.8e, %.8e, %.8e, %.8e}\n", 02299 material->specular.r, material->specular.g, 02300 material->specular.b, material->specular.a); 02301 TRACE("emissive {%.8e, %.8e, %.8e, %.8e}\n", 02302 material->emissive.r, material->emissive.g, 02303 material->emissive.b, material->emissive.a); 02304 TRACE("power %.8e.\n", material->power); 02305 02306 return WINED3D_OK; 02307 } 02308 02309 HRESULT CDECL wined3d_device_set_index_buffer(struct wined3d_device *device, 02310 struct wined3d_buffer *buffer, enum wined3d_format_id format_id) 02311 { 02312 struct wined3d_buffer *prev_buffer; 02313 02314 TRACE("device %p, buffer %p, format %s.\n", 02315 device, buffer, debug_d3dformat(format_id)); 02316 02317 prev_buffer = device->updateStateBlock->state.index_buffer; 02318 02319 device->updateStateBlock->changed.indices = TRUE; 02320 device->updateStateBlock->state.index_buffer = buffer; 02321 device->updateStateBlock->state.index_format = format_id; 02322 02323 /* Handle recording of state blocks. */ 02324 if (device->isRecordingState) 02325 { 02326 TRACE("Recording... not performing anything.\n"); 02327 if (buffer) 02328 wined3d_buffer_incref(buffer); 02329 if (prev_buffer) 02330 wined3d_buffer_decref(prev_buffer); 02331 return WINED3D_OK; 02332 } 02333 02334 if (prev_buffer != buffer) 02335 { 02336 device_invalidate_state(device, STATE_INDEXBUFFER); 02337 if (buffer) 02338 { 02339 InterlockedIncrement(&buffer->bind_count); 02340 wined3d_buffer_incref(buffer); 02341 } 02342 if (prev_buffer) 02343 { 02344 InterlockedDecrement(&prev_buffer->bind_count); 02345 wined3d_buffer_decref(prev_buffer); 02346 } 02347 } 02348 02349 return WINED3D_OK; 02350 } 02351 02352 HRESULT CDECL wined3d_device_get_index_buffer(const struct wined3d_device *device, struct wined3d_buffer **buffer) 02353 { 02354 TRACE("device %p, buffer %p.\n", device, buffer); 02355 02356 *buffer = device->stateBlock->state.index_buffer; 02357 02358 if (*buffer) 02359 wined3d_buffer_incref(*buffer); 02360 02361 TRACE("Returning %p.\n", *buffer); 02362 02363 return WINED3D_OK; 02364 } 02365 02366 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */ 02367 HRESULT CDECL wined3d_device_set_base_vertex_index(struct wined3d_device *device, INT base_index) 02368 { 02369 TRACE("device %p, base_index %d.\n", device, base_index); 02370 02371 if (device->updateStateBlock->state.base_vertex_index == base_index) 02372 { 02373 TRACE("Application is setting the old value over, nothing to do\n"); 02374 return WINED3D_OK; 02375 } 02376 02377 device->updateStateBlock->state.base_vertex_index = base_index; 02378 02379 if (device->isRecordingState) 02380 { 02381 TRACE("Recording... not performing anything\n"); 02382 return WINED3D_OK; 02383 } 02384 return WINED3D_OK; 02385 } 02386 02387 INT CDECL wined3d_device_get_base_vertex_index(const struct wined3d_device *device) 02388 { 02389 TRACE("device %p.\n", device); 02390 02391 return device->stateBlock->state.base_vertex_index; 02392 } 02393 02394 HRESULT CDECL wined3d_device_set_viewport(struct wined3d_device *device, const struct wined3d_viewport *viewport) 02395 { 02396 TRACE("device %p, viewport %p.\n", device, viewport); 02397 TRACE("x %u, y %u, w %u, h %u, min_z %.8e, max_z %.8e.\n", 02398 viewport->x, viewport->y, viewport->width, viewport->height, viewport->min_z, viewport->max_z); 02399 02400 device->updateStateBlock->changed.viewport = TRUE; 02401 device->updateStateBlock->state.viewport = *viewport; 02402 02403 /* Handle recording of state blocks */ 02404 if (device->isRecordingState) 02405 { 02406 TRACE("Recording... not performing anything\n"); 02407 return WINED3D_OK; 02408 } 02409 02410 device_invalidate_state(device, STATE_VIEWPORT); 02411 02412 return WINED3D_OK; 02413 } 02414 02415 HRESULT CDECL wined3d_device_get_viewport(const struct wined3d_device *device, struct wined3d_viewport *viewport) 02416 { 02417 TRACE("device %p, viewport %p.\n", device, viewport); 02418 02419 *viewport = device->stateBlock->state.viewport; 02420 02421 return WINED3D_OK; 02422 } 02423 02424 HRESULT CDECL wined3d_device_set_render_state(struct wined3d_device *device, 02425 enum wined3d_render_state state, DWORD value) 02426 { 02427 DWORD old_value = device->stateBlock->state.render_states[state]; 02428 02429 TRACE("device %p, state %s (%#x), value %#x.\n", device, debug_d3drenderstate(state), state, value); 02430 02431 device->updateStateBlock->changed.renderState[state >> 5] |= 1 << (state & 0x1f); 02432 device->updateStateBlock->state.render_states[state] = value; 02433 02434 /* Handle recording of state blocks. */ 02435 if (device->isRecordingState) 02436 { 02437 TRACE("Recording... not performing anything.\n"); 02438 return WINED3D_OK; 02439 } 02440 02441 /* Compared here and not before the assignment to allow proper stateblock recording. */ 02442 if (value == old_value) 02443 TRACE("Application is setting the old value over, nothing to do.\n"); 02444 else 02445 device_invalidate_state(device, STATE_RENDER(state)); 02446 02447 return WINED3D_OK; 02448 } 02449 02450 HRESULT CDECL wined3d_device_get_render_state(const struct wined3d_device *device, 02451 enum wined3d_render_state state, DWORD *value) 02452 { 02453 TRACE("device %p, state %s (%#x), value %p.\n", device, debug_d3drenderstate(state), state, value); 02454 02455 *value = device->stateBlock->state.render_states[state]; 02456 02457 return WINED3D_OK; 02458 } 02459 02460 HRESULT CDECL wined3d_device_set_sampler_state(struct wined3d_device *device, 02461 UINT sampler_idx, enum wined3d_sampler_state state, DWORD value) 02462 { 02463 DWORD old_value; 02464 02465 TRACE("device %p, sampler_idx %u, state %s, value %#x.\n", 02466 device, sampler_idx, debug_d3dsamplerstate(state), value); 02467 02468 if (sampler_idx >= WINED3DVERTEXTEXTURESAMPLER0 && sampler_idx <= WINED3DVERTEXTEXTURESAMPLER3) 02469 sampler_idx -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS); 02470 02471 if (sampler_idx >= sizeof(device->stateBlock->state.sampler_states) 02472 / sizeof(*device->stateBlock->state.sampler_states)) 02473 { 02474 WARN("Invalid sampler %u.\n", sampler_idx); 02475 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */ 02476 } 02477 02478 old_value = device->stateBlock->state.sampler_states[sampler_idx][state]; 02479 device->updateStateBlock->state.sampler_states[sampler_idx][state] = value; 02480 device->updateStateBlock->changed.samplerState[sampler_idx] |= 1 << state; 02481 02482 /* Handle recording of state blocks. */ 02483 if (device->isRecordingState) 02484 { 02485 TRACE("Recording... not performing anything.\n"); 02486 return WINED3D_OK; 02487 } 02488 02489 if (old_value == value) 02490 { 02491 TRACE("Application is setting the old value over, nothing to do.\n"); 02492 return WINED3D_OK; 02493 } 02494 02495 device_invalidate_state(device, STATE_SAMPLER(sampler_idx)); 02496 02497 return WINED3D_OK; 02498 } 02499 02500 HRESULT CDECL wined3d_device_get_sampler_state(const struct wined3d_device *device, 02501 UINT sampler_idx, enum wined3d_sampler_state state, DWORD *value) 02502 { 02503 TRACE("device %p, sampler_idx %u, state %s, value %p.\n", 02504 device, sampler_idx, debug_d3dsamplerstate(state), value); 02505 02506 if (sampler_idx >= WINED3DVERTEXTEXTURESAMPLER0 && sampler_idx <= WINED3DVERTEXTEXTURESAMPLER3) 02507 sampler_idx -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS); 02508 02509 if (sampler_idx >= sizeof(device->stateBlock->state.sampler_states) 02510 / sizeof(*device->stateBlock->state.sampler_states)) 02511 { 02512 WARN("Invalid sampler %u.\n", sampler_idx); 02513 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */ 02514 } 02515 02516 *value = device->stateBlock->state.sampler_states[sampler_idx][state]; 02517 TRACE("Returning %#x.\n", *value); 02518 02519 return WINED3D_OK; 02520 } 02521 02522 HRESULT CDECL wined3d_device_set_scissor_rect(struct wined3d_device *device, const RECT *rect) 02523 { 02524 TRACE("device %p, rect %s.\n", device, wine_dbgstr_rect(rect)); 02525 02526 device->updateStateBlock->changed.scissorRect = TRUE; 02527 if (EqualRect(&device->updateStateBlock->state.scissor_rect, rect)) 02528 { 02529 TRACE("App is setting the old scissor rectangle over, nothing to do.\n"); 02530 return WINED3D_OK; 02531 } 02532 CopyRect(&device->updateStateBlock->state.scissor_rect, rect); 02533 02534 if (device->isRecordingState) 02535 { 02536 TRACE("Recording... not performing anything.\n"); 02537 return WINED3D_OK; 02538 } 02539 02540 device_invalidate_state(device, STATE_SCISSORRECT); 02541 02542 return WINED3D_OK; 02543 } 02544 02545 HRESULT CDECL wined3d_device_get_scissor_rect(const struct wined3d_device *device, RECT *rect) 02546 { 02547 TRACE("device %p, rect %p.\n", device, rect); 02548 02549 *rect = device->updateStateBlock->state.scissor_rect; 02550 TRACE("Returning rect %s.\n", wine_dbgstr_rect(rect)); 02551 02552 return WINED3D_OK; 02553 } 02554 02555 HRESULT CDECL wined3d_device_set_vertex_declaration(struct wined3d_device *device, 02556 struct wined3d_vertex_declaration *declaration) 02557 { 02558 struct wined3d_vertex_declaration *prev = device->updateStateBlock->state.vertex_declaration; 02559 02560 TRACE("device %p, declaration %p.\n", device, declaration); 02561 02562 if (declaration) 02563 wined3d_vertex_declaration_incref(declaration); 02564 if (prev) 02565 wined3d_vertex_declaration_decref(prev); 02566 02567 device->updateStateBlock->state.vertex_declaration = declaration; 02568 device->updateStateBlock->changed.vertexDecl = TRUE; 02569 02570 if (device->isRecordingState) 02571 { 02572 TRACE("Recording... not performing anything.\n"); 02573 return WINED3D_OK; 02574 } 02575 else if (declaration == prev) 02576 { 02577 /* Checked after the assignment to allow proper stateblock recording. */ 02578 TRACE("Application is setting the old declaration over, nothing to do.\n"); 02579 return WINED3D_OK; 02580 } 02581 02582 device_invalidate_state(device, STATE_VDECL); 02583 return WINED3D_OK; 02584 } 02585 02586 HRESULT CDECL wined3d_device_get_vertex_declaration(const struct wined3d_device *device, 02587 struct wined3d_vertex_declaration **declaration) 02588 { 02589 TRACE("device %p, declaration %p.\n", device, declaration); 02590 02591 *declaration = device->stateBlock->state.vertex_declaration; 02592 if (*declaration) 02593 wined3d_vertex_declaration_incref(*declaration); 02594 02595 return WINED3D_OK; 02596 } 02597 02598 HRESULT CDECL wined3d_device_set_vertex_shader(struct wined3d_device *device, struct wined3d_shader *shader) 02599 { 02600 struct wined3d_shader *prev = device->updateStateBlock->state.vertex_shader; 02601 02602 TRACE("device %p, shader %p.\n", device, shader); 02603 02604 device->updateStateBlock->state.vertex_shader = shader; 02605 device->updateStateBlock->changed.vertexShader = TRUE; 02606 02607 if (device->isRecordingState) 02608 { 02609 if (shader) 02610 wined3d_shader_incref(shader); 02611 if (prev) 02612 wined3d_shader_decref(prev); 02613 TRACE("Recording... not performing anything.\n"); 02614 return WINED3D_OK; 02615 } 02616 02617 if (shader == prev) 02618 { 02619 TRACE("Application is setting the old shader over, nothing to do.\n"); 02620 return WINED3D_OK; 02621 } 02622 02623 if (shader) 02624 wined3d_shader_incref(shader); 02625 if (prev) 02626 wined3d_shader_decref(prev); 02627 02628 device_invalidate_state(device, STATE_VSHADER); 02629 02630 return WINED3D_OK; 02631 } 02632 02633 struct wined3d_shader * CDECL wined3d_device_get_vertex_shader(const struct wined3d_device *device) 02634 { 02635 struct wined3d_shader *shader; 02636 02637 TRACE("device %p.\n", device); 02638 02639 shader = device->stateBlock->state.vertex_shader; 02640 if (shader) 02641 wined3d_shader_incref(shader); 02642 02643 TRACE("Returning %p.\n", shader); 02644 return shader; 02645 } 02646 02647 HRESULT CDECL wined3d_device_set_vs_consts_b(struct wined3d_device *device, 02648 UINT start_register, const BOOL *constants, UINT bool_count) 02649 { 02650 UINT count = min(bool_count, MAX_CONST_B - start_register); 02651 UINT i; 02652 02653 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n", 02654 device, start_register, constants, bool_count); 02655 02656 if (!constants || start_register >= MAX_CONST_B) 02657 return WINED3DERR_INVALIDCALL; 02658 02659 memcpy(&device->updateStateBlock->state.vs_consts_b[start_register], constants, count * sizeof(BOOL)); 02660 for (i = 0; i < count; ++i) 02661 TRACE("Set BOOL constant %u to %s.\n", start_register + i, constants[i] ? "true" : "false"); 02662 02663 for (i = start_register; i < count + start_register; ++i) 02664 device->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i); 02665 02666 if (!device->isRecordingState) 02667 device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT); 02668 02669 return WINED3D_OK; 02670 } 02671 02672 HRESULT CDECL wined3d_device_get_vs_consts_b(const struct wined3d_device *device, 02673 UINT start_register, BOOL *constants, UINT bool_count) 02674 { 02675 UINT count = min(bool_count, MAX_CONST_B - start_register); 02676 02677 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n", 02678 device, start_register, constants, bool_count); 02679 02680 if (!constants || start_register >= MAX_CONST_B) 02681 return WINED3DERR_INVALIDCALL; 02682 02683 memcpy(constants, &device->stateBlock->state.vs_consts_b[start_register], count * sizeof(BOOL)); 02684 02685 return WINED3D_OK; 02686 } 02687 02688 HRESULT CDECL wined3d_device_set_vs_consts_i(struct wined3d_device *device, 02689 UINT start_register, const int *constants, UINT vector4i_count) 02690 { 02691 UINT count = min(vector4i_count, MAX_CONST_I - start_register); 02692 UINT i; 02693 02694 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n", 02695 device, start_register, constants, vector4i_count); 02696 02697 if (!constants || start_register >= MAX_CONST_I) 02698 return WINED3DERR_INVALIDCALL; 02699 02700 memcpy(&device->updateStateBlock->state.vs_consts_i[start_register * 4], constants, count * sizeof(int) * 4); 02701 for (i = 0; i < count; ++i) 02702 TRACE("Set INT constant %u to {%d, %d, %d, %d}.\n", start_register + i, 02703 constants[i * 4], constants[i * 4 + 1], 02704 constants[i * 4 + 2], constants[i * 4 + 3]); 02705 02706 for (i = start_register; i < count + start_register; ++i) 02707 device->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i); 02708 02709 if (!device->isRecordingState) 02710 device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT); 02711 02712 return WINED3D_OK; 02713 } 02714 02715 HRESULT CDECL wined3d_device_get_vs_consts_i(const struct wined3d_device *device, 02716 UINT start_register, int *constants, UINT vector4i_count) 02717 { 02718 UINT count = min(vector4i_count, MAX_CONST_I - start_register); 02719 02720 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n", 02721 device, start_register, constants, vector4i_count); 02722 02723 if (!constants || start_register >= MAX_CONST_I) 02724 return WINED3DERR_INVALIDCALL; 02725 02726 memcpy(constants, &device->stateBlock->state.vs_consts_i[start_register * 4], count * sizeof(int) * 4); 02727 return WINED3D_OK; 02728 } 02729 02730 HRESULT CDECL wined3d_device_set_vs_consts_f(struct wined3d_device *device, 02731 UINT start_register, const float *constants, UINT vector4f_count) 02732 { 02733 UINT i; 02734 02735 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n", 02736 device, start_register, constants, vector4f_count); 02737 02738 /* Specifically test start_register > limit to catch MAX_UINT overflows 02739 * when adding start_register + vector4f_count. */ 02740 if (!constants 02741 || start_register + vector4f_count > device->d3d_vshader_constantF 02742 || start_register > device->d3d_vshader_constantF) 02743 return WINED3DERR_INVALIDCALL; 02744 02745 memcpy(&device->updateStateBlock->state.vs_consts_f[start_register * 4], 02746 constants, vector4f_count * sizeof(float) * 4); 02747 if (TRACE_ON(d3d)) 02748 { 02749 for (i = 0; i < vector4f_count; ++i) 02750 TRACE("Set FLOAT constant %u to {%.8e, %.8e, %.8e, %.8e}.\n", start_register + i, 02751 constants[i * 4], constants[i * 4 + 1], 02752 constants[i * 4 + 2], constants[i * 4 + 3]); 02753 } 02754 02755 if (!device->isRecordingState) 02756 { 02757 device->shader_backend->shader_update_float_vertex_constants(device, start_register, vector4f_count); 02758 device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT); 02759 } 02760 02761 memset(device->updateStateBlock->changed.vertexShaderConstantsF + start_register, 1, 02762 sizeof(*device->updateStateBlock->changed.vertexShaderConstantsF) * vector4f_count); 02763 02764 return WINED3D_OK; 02765 } 02766 02767 HRESULT CDECL wined3d_device_get_vs_consts_f(const struct wined3d_device *device, 02768 UINT start_register, float *constants, UINT vector4f_count) 02769 { 02770 int count = min(vector4f_count, device->d3d_vshader_constantF - start_register); 02771 02772 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n", 02773 device, start_register, constants, vector4f_count); 02774 02775 if (!constants || count < 0) 02776 return WINED3DERR_INVALIDCALL; 02777 02778 memcpy(constants, &device->stateBlock->state.vs_consts_f[start_register * 4], count * sizeof(float) * 4); 02779 02780 return WINED3D_OK; 02781 } 02782 02783 static void device_invalidate_texture_stage(const struct wined3d_device *device, DWORD stage) 02784 { 02785 DWORD i; 02786 02787 for (i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i) 02788 { 02789 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, i)); 02790 } 02791 } 02792 02793 static void device_map_stage(struct wined3d_device *device, DWORD stage, DWORD unit) 02794 { 02795 DWORD i = device->rev_tex_unit_map[unit]; 02796 DWORD j = device->texUnitMap[stage]; 02797 02798 device->texUnitMap[stage] = unit; 02799 if (i != WINED3D_UNMAPPED_STAGE && i != stage) 02800 device->texUnitMap[i] = WINED3D_UNMAPPED_STAGE; 02801 02802 device->rev_tex_unit_map[unit] = stage; 02803 if (j != WINED3D_UNMAPPED_STAGE && j != unit) 02804 device->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE; 02805 } 02806 02807 static void device_update_fixed_function_usage_map(struct wined3d_device *device) 02808 { 02809 UINT i; 02810 02811 device->fixed_function_usage_map = 0; 02812 for (i = 0; i < MAX_TEXTURES; ++i) 02813 { 02814 const struct wined3d_state *state = &device->stateBlock->state; 02815 enum wined3d_texture_op color_op = state->texture_states[i][WINED3D_TSS_COLOR_OP]; 02816 enum wined3d_texture_op alpha_op = state->texture_states[i][WINED3D_TSS_ALPHA_OP]; 02817 DWORD color_arg1 = state->texture_states[i][WINED3D_TSS_COLOR_ARG1] & WINED3DTA_SELECTMASK; 02818 DWORD color_arg2 = state->texture_states[i][WINED3D_TSS_COLOR_ARG2] & WINED3DTA_SELECTMASK; 02819 DWORD color_arg3 = state->texture_states[i][WINED3D_TSS_COLOR_ARG0] & WINED3DTA_SELECTMASK; 02820 DWORD alpha_arg1 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG1] & WINED3DTA_SELECTMASK; 02821 DWORD alpha_arg2 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG2] & WINED3DTA_SELECTMASK; 02822 DWORD alpha_arg3 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG0] & WINED3DTA_SELECTMASK; 02823 02824 /* Not used, and disable higher stages. */ 02825 if (color_op == WINED3D_TOP_DISABLE) 02826 break; 02827 02828 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG2) 02829 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG1) 02830 || ((color_arg3 == WINED3DTA_TEXTURE) 02831 && (color_op == WINED3D_TOP_MULTIPLY_ADD || color_op == WINED3D_TOP_LERP)) 02832 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG2) 02833 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG1) 02834 || ((alpha_arg3 == WINED3DTA_TEXTURE) 02835 && (alpha_op == WINED3D_TOP_MULTIPLY_ADD || alpha_op == WINED3D_TOP_LERP))) 02836 device->fixed_function_usage_map |= (1 << i); 02837 02838 if ((color_op == WINED3D_TOP_BUMPENVMAP || color_op == WINED3D_TOP_BUMPENVMAP_LUMINANCE) 02839 && i < MAX_TEXTURES - 1) 02840 device->fixed_function_usage_map |= (1 << (i + 1)); 02841 } 02842 } 02843 02844 static void device_map_fixed_function_samplers(struct wined3d_device *device, const struct wined3d_gl_info *gl_info) 02845 { 02846 unsigned int i, tex; 02847 WORD ffu_map; 02848 02849 device_update_fixed_function_usage_map(device); 02850 ffu_map = device->fixed_function_usage_map; 02851 02852 if (device->max_ffp_textures == gl_info->limits.texture_stages 02853 || device->stateBlock->state.lowest_disabled_stage <= device->max_ffp_textures) 02854 { 02855 for (i = 0; ffu_map; ffu_map >>= 1, ++i) 02856 { 02857 if (!(ffu_map & 1)) continue; 02858 02859 if (device->texUnitMap[i] != i) 02860 { 02861 device_map_stage(device, i, i); 02862 device_invalidate_state(device, STATE_SAMPLER(i)); 02863 device_invalidate_texture_stage(device, i); 02864 } 02865 } 02866 return; 02867 } 02868 02869 /* Now work out the mapping */ 02870 tex = 0; 02871 for (i = 0; ffu_map; ffu_map >>= 1, ++i) 02872 { 02873 if (!(ffu_map & 1)) continue; 02874 02875 if (device->texUnitMap[i] != tex) 02876 { 02877 device_map_stage(device, i, tex); 02878 device_invalidate_state(device, STATE_SAMPLER(i)); 02879 device_invalidate_texture_stage(device, i); 02880 } 02881 02882 ++tex; 02883 } 02884 } 02885 02886 static void device_map_psamplers(struct wined3d_device *device, const struct wined3d_gl_info *gl_info) 02887 { 02888 const enum wined3d_sampler_texture_type *sampler_type = 02889 device->stateBlock->state.pixel_shader->reg_maps.sampler_type; 02890 unsigned int i; 02891 02892 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) 02893 { 02894 if (sampler_type[i] && device->texUnitMap[i] != i) 02895 { 02896 device_map_stage(device, i, i); 02897 device_invalidate_state(device, STATE_SAMPLER(i)); 02898 if (i < gl_info->limits.texture_stages) 02899 device_invalidate_texture_stage(device, i); 02900 } 02901 } 02902 } 02903 02904 static BOOL device_unit_free_for_vs(const struct wined3d_device *device, 02905 const enum wined3d_sampler_texture_type *pshader_sampler_tokens, 02906 const enum wined3d_sampler_texture_type *vshader_sampler_tokens, DWORD unit) 02907 { 02908 DWORD current_mapping = device->rev_tex_unit_map[unit]; 02909 02910 /* Not currently used */ 02911 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE; 02912 02913 if (current_mapping < MAX_FRAGMENT_SAMPLERS) { 02914 /* Used by a fragment sampler */ 02915 02916 if (!pshader_sampler_tokens) { 02917 /* No pixel shader, check fixed function */ 02918 return current_mapping >= MAX_TEXTURES || !(device->fixed_function_usage_map & (1 << current_mapping)); 02919 } 02920 02921 /* Pixel shader, check the shader's sampler map */ 02922 return !pshader_sampler_tokens[current_mapping]; 02923 } 02924 02925 /* Used by a vertex sampler */ 02926 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS]; 02927 } 02928 02929 static void device_map_vsamplers(struct wined3d_device *device, BOOL ps, const struct wined3d_gl_info *gl_info) 02930 { 02931 const enum wined3d_sampler_texture_type *vshader_sampler_type = 02932 device->stateBlock->state.vertex_shader->reg_maps.sampler_type; 02933 const enum wined3d_sampler_texture_type *pshader_sampler_type = NULL; 02934 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1; 02935 int i; 02936 02937 if (ps) 02938 { 02939 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type. 02940 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */ 02941 pshader_sampler_type = device->stateBlock->state.pixel_shader->reg_maps.sampler_type; 02942 } 02943 02944 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) { 02945 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS; 02946 if (vshader_sampler_type[i]) 02947 { 02948 if (device->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE) 02949 { 02950 /* Already mapped somewhere */ 02951 continue; 02952 } 02953 02954 while (start >= 0) 02955 { 02956 if (device_unit_free_for_vs(device, pshader_sampler_type, vshader_sampler_type, start)) 02957 { 02958 device_map_stage(device, vsampler_idx, start); 02959 device_invalidate_state(device, STATE_SAMPLER(vsampler_idx)); 02960 02961 --start; 02962 break; 02963 } 02964 02965 --start; 02966 } 02967 } 02968 } 02969 } 02970 02971 void device_update_tex_unit_map(struct wined3d_device *device) 02972 { 02973 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 02974 const struct wined3d_state *state = &device->stateBlock->state; 02975 BOOL vs = use_vs(state); 02976 BOOL ps = use_ps(state); 02977 /* 02978 * Rules are: 02979 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but 02980 * that would be really messy and require shader recompilation 02981 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have 02982 * to be reset. Because of that try to work with a 1:1 mapping as much as possible 02983 */ 02984 if (ps) 02985 device_map_psamplers(device, gl_info); 02986 else 02987 device_map_fixed_function_samplers(device, gl_info); 02988 02989 if (vs) 02990 device_map_vsamplers(device, ps, gl_info); 02991 } 02992 02993 HRESULT CDECL wined3d_device_set_pixel_shader(struct wined3d_device *device, struct wined3d_shader *shader) 02994 { 02995 struct wined3d_shader *prev = device->updateStateBlock->state.pixel_shader; 02996 02997 TRACE("device %p, shader %p.\n", device, shader); 02998 02999 device->updateStateBlock->state.pixel_shader = shader; 03000 device->updateStateBlock->changed.pixelShader = TRUE; 03001 03002 if (device->isRecordingState) 03003 { 03004 if (shader) 03005 wined3d_shader_incref(shader); 03006 if (prev) 03007 wined3d_shader_decref(prev); 03008 TRACE("Recording... not performing anything.\n"); 03009 return WINED3D_OK; 03010 } 03011 03012 if (shader == prev) 03013 { 03014 TRACE("Application is setting the old shader over, nothing to do.\n"); 03015 return WINED3D_OK; 03016 } 03017 03018 if (shader) 03019 wined3d_shader_incref(shader); 03020 if (prev) 03021 wined3d_shader_decref(prev); 03022 03023 device_invalidate_state(device, STATE_PIXELSHADER); 03024 03025 return WINED3D_OK; 03026 } 03027 03028 struct wined3d_shader * CDECL wined3d_device_get_pixel_shader(const struct wined3d_device *device) 03029 { 03030 struct wined3d_shader *shader; 03031 03032 TRACE("device %p.\n", device); 03033 03034 shader = device->stateBlock->state.pixel_shader; 03035 if (shader) 03036 wined3d_shader_incref(shader); 03037 03038 TRACE("Returning %p.\n", shader); 03039 return shader; 03040 } 03041 03042 HRESULT CDECL wined3d_device_set_ps_consts_b(struct wined3d_device *device, 03043 UINT start_register, const BOOL *constants, UINT bool_count) 03044 { 03045 UINT count = min(bool_count, MAX_CONST_B - start_register); 03046 UINT i; 03047 03048 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n", 03049 device, start_register, constants, bool_count); 03050 03051 if (!constants || start_register >= MAX_CONST_B) 03052 return WINED3DERR_INVALIDCALL; 03053 03054 memcpy(&device->updateStateBlock->state.ps_consts_b[start_register], constants, count * sizeof(BOOL)); 03055 for (i = 0; i < count; ++i) 03056 TRACE("Set BOOL constant %u to %s.\n", start_register + i, constants[i] ? "true" : "false"); 03057 03058 for (i = start_register; i < count + start_register; ++i) 03059 device->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i); 03060 03061 if (!device->isRecordingState) 03062 device_invalidate_state(device, STATE_PIXELSHADERCONSTANT); 03063 03064 return WINED3D_OK; 03065 } 03066 03067 HRESULT CDECL wined3d_device_get_ps_consts_b(const struct wined3d_device *device, 03068 UINT start_register, BOOL *constants, UINT bool_count) 03069 { 03070 UINT count = min(bool_count, MAX_CONST_B - start_register); 03071 03072 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n", 03073 device, start_register, constants, bool_count); 03074 03075 if (!constants || start_register >= MAX_CONST_B) 03076 return WINED3DERR_INVALIDCALL; 03077 03078 memcpy(constants, &device->stateBlock->state.ps_consts_b[start_register], count * sizeof(BOOL)); 03079 03080 return WINED3D_OK; 03081 } 03082 03083 HRESULT CDECL wined3d_device_set_ps_consts_i(struct wined3d_device *device, 03084 UINT start_register, const int *constants, UINT vector4i_count) 03085 { 03086 UINT count = min(vector4i_count, MAX_CONST_I - start_register); 03087 UINT i; 03088 03089 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n", 03090 device, start_register, constants, vector4i_count); 03091 03092 if (!constants || start_register >= MAX_CONST_I) 03093 return WINED3DERR_INVALIDCALL; 03094 03095 memcpy(&device->updateStateBlock->state.ps_consts_i[start_register * 4], constants, count * sizeof(int) * 4); 03096 for (i = 0; i < count; ++i) 03097 TRACE("Set INT constant %u to {%d, %d, %d, %d}.\n", start_register + i, 03098 constants[i * 4], constants[i * 4 + 1], 03099 constants[i * 4 + 2], constants[i * 4 + 3]); 03100 03101 for (i = start_register; i < count + start_register; ++i) 03102 device->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i); 03103 03104 if (!device->isRecordingState) 03105 device_invalidate_state(device, STATE_PIXELSHADERCONSTANT); 03106 03107 return WINED3D_OK; 03108 } 03109 03110 HRESULT CDECL wined3d_device_get_ps_consts_i(const struct wined3d_device *device, 03111 UINT start_register, int *constants, UINT vector4i_count) 03112 { 03113 UINT count = min(vector4i_count, MAX_CONST_I - start_register); 03114 03115 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n", 03116 device, start_register, constants, vector4i_count); 03117 03118 if (!constants || start_register >= MAX_CONST_I) 03119 return WINED3DERR_INVALIDCALL; 03120 03121 memcpy(constants, &device->stateBlock->state.ps_consts_i[start_register * 4], count * sizeof(int) * 4); 03122 03123 return WINED3D_OK; 03124 } 03125 03126 HRESULT CDECL wined3d_device_set_ps_consts_f(struct wined3d_device *device, 03127 UINT start_register, const float *constants, UINT vector4f_count) 03128 { 03129 UINT i; 03130 03131 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n", 03132 device, start_register, constants, vector4f_count); 03133 03134 /* Specifically test start_register > limit to catch MAX_UINT overflows 03135 * when adding start_register + vector4f_count. */ 03136 if (!constants 03137 || start_register + vector4f_count > device->d3d_pshader_constantF 03138 || start_register > device->d3d_pshader_constantF) 03139 return WINED3DERR_INVALIDCALL; 03140 03141 memcpy(&device->updateStateBlock->state.ps_consts_f[start_register * 4], 03142 constants, vector4f_count * sizeof(float) * 4); 03143 if (TRACE_ON(d3d)) 03144 { 03145 for (i = 0; i < vector4f_count; ++i) 03146 TRACE("Set FLOAT constant %u to {%.8e, %.8e, %.8e, %.8e}.\n", start_register + i, 03147 constants[i * 4], constants[i * 4 + 1], 03148 constants[i * 4 + 2], constants[i * 4 + 3]); 03149 } 03150 03151 if (!device->isRecordingState) 03152 { 03153 device->shader_backend->shader_update_float_pixel_constants(device, start_register, vector4f_count); 03154 device_invalidate_state(device, STATE_PIXELSHADERCONSTANT); 03155 } 03156 03157 memset(device->updateStateBlock->changed.pixelShaderConstantsF + start_register, 1, 03158 sizeof(*device->updateStateBlock->changed.pixelShaderConstantsF) * vector4f_count); 03159 03160 return WINED3D_OK; 03161 } 03162 03163 HRESULT CDECL wined3d_device_get_ps_consts_f(const struct wined3d_device *device, 03164 UINT start_register, float *constants, UINT vector4f_count) 03165 { 03166 int count = min(vector4f_count, device->d3d_pshader_constantF - start_register); 03167 03168 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n", 03169 device, start_register, constants, vector4f_count); 03170 03171 if (!constants || count < 0) 03172 return WINED3DERR_INVALIDCALL; 03173 03174 memcpy(constants, &device->stateBlock->state.ps_consts_f[start_register * 4], count * sizeof(float) * 4); 03175 03176 return WINED3D_OK; 03177 } 03178 03179 /* Context activation is done by the caller. */ 03180 /* Do not call while under the GL lock. */ 03181 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size) 03182 static HRESULT process_vertices_strided(const struct wined3d_device *device, DWORD dwDestIndex, DWORD dwCount, 03183 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags, 03184 DWORD DestFVF) 03185 { 03186 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 03187 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL; 03188 struct wined3d_matrix mat, proj_mat, view_mat, world_mat; 03189 struct wined3d_viewport vp; 03190 unsigned int i; 03191 BOOL doClip; 03192 DWORD numTextures; 03193 03194 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL)) 03195 { 03196 WARN(" lighting state not saved yet... Some strange stuff may happen !\n"); 03197 } 03198 03199 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION))) 03200 { 03201 ERR("Source has no position mask\n"); 03202 return WINED3DERR_INVALIDCALL; 03203 } 03204 03205 if (!dest->resource.allocatedMemory) 03206 buffer_get_sysmem(dest, gl_info); 03207 03208 /* Get a pointer into the destination vbo(create one if none exists) and 03209 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast 03210 */ 03211 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT]) 03212 { 03213 dest->flags |= WINED3D_BUFFER_CREATEBO; 03214 wined3d_buffer_preload(dest); 03215 } 03216 03217 if (dest->buffer_object) 03218 { 03219 unsigned char extrabytes = 0; 03220 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW 03221 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data, 03222 * this may write 4 extra bytes beyond the area that should be written 03223 */ 03224 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4; 03225 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes); 03226 if(!dest_conv_addr) { 03227 ERR("Out of memory\n"); 03228 /* Continue without storing converted vertices */ 03229 } 03230 dest_conv = dest_conv_addr; 03231 } 03232 03233 if (device->stateBlock->state.render_states[WINED3D_RS_CLIPPING]) 03234 { 03235 static BOOL warned = FALSE; 03236 /* 03237 * The clipping code is not quite correct. Some things need 03238 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9, 03239 * so disable clipping for now. 03240 * (The graphics in Half-Life are broken, and my processvertices 03241 * test crashes with IDirect3DDevice3) 03242 doClip = TRUE; 03243 */ 03244 doClip = FALSE; 03245 if(!warned) { 03246 warned = TRUE; 03247 FIXME("Clipping is broken and disabled for now\n"); 03248 } 03249 } else doClip = FALSE; 03250 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF); 03251 03252 wined3d_device_get_transform(device, WINED3D_TS_VIEW, &view_mat); 03253 wined3d_device_get_transform(device, WINED3D_TS_PROJECTION, &proj_mat); 03254 wined3d_device_get_transform(device, WINED3D_TS_WORLD_MATRIX(0), &world_mat); 03255 03256 TRACE("View mat:\n"); 03257 TRACE("%f %f %f %f\n", view_mat.u.s._11, view_mat.u.s._12, view_mat.u.s._13, view_mat.u.s._14); 03258 TRACE("%f %f %f %f\n", view_mat.u.s._21, view_mat.u.s._22, view_mat.u.s._23, view_mat.u.s._24); 03259 TRACE("%f %f %f %f\n", view_mat.u.s._31, view_mat.u.s._32, view_mat.u.s._33, view_mat.u.s._34); 03260 TRACE("%f %f %f %f\n", view_mat.u.s._41, view_mat.u.s._42, view_mat.u.s._43, view_mat.u.s._44); 03261 03262 TRACE("Proj mat:\n"); 03263 TRACE("%f %f %f %f\n", proj_mat.u.s._11, proj_mat.u.s._12, proj_mat.u.s._13, proj_mat.u.s._14); 03264 TRACE("%f %f %f %f\n", proj_mat.u.s._21, proj_mat.u.s._22, proj_mat.u.s._23, proj_mat.u.s._24); 03265 TRACE("%f %f %f %f\n", proj_mat.u.s._31, proj_mat.u.s._32, proj_mat.u.s._33, proj_mat.u.s._34); 03266 TRACE("%f %f %f %f\n", proj_mat.u.s._41, proj_mat.u.s._42, proj_mat.u.s._43, proj_mat.u.s._44); 03267 03268 TRACE("World mat:\n"); 03269 TRACE("%f %f %f %f\n", world_mat.u.s._11, world_mat.u.s._12, world_mat.u.s._13, world_mat.u.s._14); 03270 TRACE("%f %f %f %f\n", world_mat.u.s._21, world_mat.u.s._22, world_mat.u.s._23, world_mat.u.s._24); 03271 TRACE("%f %f %f %f\n", world_mat.u.s._31, world_mat.u.s._32, world_mat.u.s._33, world_mat.u.s._34); 03272 TRACE("%f %f %f %f\n", world_mat.u.s._41, world_mat.u.s._42, world_mat.u.s._43, world_mat.u.s._44); 03273 03274 /* Get the viewport */ 03275 wined3d_device_get_viewport(device, &vp); 03276 TRACE("viewport x %u, y %u, width %u, height %u, min_z %.8e, max_z %.8e.\n", 03277 vp.x, vp.y, vp.width, vp.height, vp.min_z, vp.max_z); 03278 03279 multiply_matrix(&mat,&view_mat,&world_mat); 03280 multiply_matrix(&mat,&proj_mat,&mat); 03281 03282 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT; 03283 03284 for (i = 0; i < dwCount; i+= 1) { 03285 unsigned int tex_index; 03286 03287 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) || 03288 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) { 03289 /* The position first */ 03290 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION]; 03291 const float *p = (const float *)(element->data.addr + i * element->stride); 03292 float x, y, z, rhw; 03293 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]); 03294 03295 /* Multiplication with world, view and projection matrix */ 03296 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0f * mat.u.s._41); 03297 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0f * mat.u.s._42); 03298 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0f * mat.u.s._43); 03299 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0f * mat.u.s._44); 03300 03301 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw); 03302 03303 /* WARNING: The following things are taken from d3d7 and were not yet checked 03304 * against d3d8 or d3d9! 03305 */ 03306 03307 /* Clipping conditions: From msdn 03308 * 03309 * A vertex is clipped if it does not match the following requirements 03310 * -rhw < x <= rhw 03311 * -rhw < y <= rhw 03312 * 0 < z <= rhw 03313 * 0 < rhw ( Not in d3d7, but tested in d3d7) 03314 * 03315 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and 03316 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked) 03317 * 03318 */ 03319 03320 if( !doClip || 03321 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) && 03322 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) && 03323 ( rhw > eps ) ) ) { 03324 03325 /* "Normal" viewport transformation (not clipped) 03326 * 1) The values are divided by rhw 03327 * 2) The y axis is negative, so multiply it with -1 03328 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and 03329 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ 03330 * 4) Multiply x with Width/2 and add Width/2 03331 * 5) The same for the height 03332 * 6) Add the viewpoint X and Y to the 2D coordinates and 03333 * The minimum Z value to z 03334 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W.... 03335 * 03336 * Well, basically it's simply a linear transformation into viewport 03337 * coordinates 03338 */ 03339 03340 x /= rhw; 03341 y /= rhw; 03342 z /= rhw; 03343 03344 y *= -1; 03345 03346 x *= vp.width / 2; 03347 y *= vp.height / 2; 03348 z *= vp.max_z - vp.min_z; 03349 03350 x += vp.width / 2 + vp.x; 03351 y += vp.height / 2 + vp.y; 03352 z += vp.min_z; 03353 03354 rhw = 1 / rhw; 03355 } else { 03356 /* That vertex got clipped 03357 * Contrary to OpenGL it is not dropped completely, it just 03358 * undergoes a different calculation. 03359 */ 03360 TRACE("Vertex got clipped\n"); 03361 x += rhw; 03362 y += rhw; 03363 03364 x /= 2; 03365 y /= 2; 03366 03367 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices 03368 * outside of the main vertex buffer memory. That needs some more 03369 * investigation... 03370 */ 03371 } 03372 03373 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw); 03374 03375 03376 ( (float *) dest_ptr)[0] = x; 03377 ( (float *) dest_ptr)[1] = y; 03378 ( (float *) dest_ptr)[2] = z; 03379 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */ 03380 03381 dest_ptr += 3 * sizeof(float); 03382 03383 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) { 03384 dest_ptr += sizeof(float); 03385 } 03386 03387 if(dest_conv) { 03388 float w = 1 / rhw; 03389 ( (float *) dest_conv)[0] = x * w; 03390 ( (float *) dest_conv)[1] = y * w; 03391 ( (float *) dest_conv)[2] = z * w; 03392 ( (float *) dest_conv)[3] = w; 03393 03394 dest_conv += 3 * sizeof(float); 03395 03396 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) { 03397 dest_conv += sizeof(float); 03398 } 03399 } 03400 } 03401 if (DestFVF & WINED3DFVF_PSIZE) { 03402 dest_ptr += sizeof(DWORD); 03403 if(dest_conv) dest_conv += sizeof(DWORD); 03404 } 03405 if (DestFVF & WINED3DFVF_NORMAL) 03406 { 03407 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL]; 03408 const float *normal = (const float *)(element->data.addr + i * element->stride); 03409 /* AFAIK this should go into the lighting information */ 03410 FIXME("Didn't expect the destination to have a normal\n"); 03411 copy_and_next(dest_ptr, normal, 3 * sizeof(float)); 03412 if(dest_conv) { 03413 copy_and_next(dest_conv, normal, 3 * sizeof(float)); 03414 } 03415 } 03416 03417 if (DestFVF & WINED3DFVF_DIFFUSE) 03418 { 03419 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE]; 03420 const DWORD *color_d = (const DWORD *)(element->data.addr + i * element->stride); 03421 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE))) 03422 { 03423 static BOOL warned = FALSE; 03424 03425 if(!warned) { 03426 ERR("No diffuse color in source, but destination has one\n"); 03427 warned = TRUE; 03428 } 03429 03430 *( (DWORD *) dest_ptr) = 0xffffffff; 03431 dest_ptr += sizeof(DWORD); 03432 03433 if(dest_conv) { 03434 *( (DWORD *) dest_conv) = 0xffffffff; 03435 dest_conv += sizeof(DWORD); 03436 } 03437 } 03438 else { 03439 copy_and_next(dest_ptr, color_d, sizeof(DWORD)); 03440 if(dest_conv) { 03441 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */ 03442 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */ 03443 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */ 03444 dest_conv += sizeof(DWORD); 03445 } 03446 } 03447 } 03448 03449 if (DestFVF & WINED3DFVF_SPECULAR) 03450 { 03451 /* What's the color value in the feedback buffer? */ 03452 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR]; 03453 const DWORD *color_s = (const DWORD *)(element->data.addr + i * element->stride); 03454 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR))) 03455 { 03456 static BOOL warned = FALSE; 03457 03458 if(!warned) { 03459 ERR("No specular color in source, but destination has one\n"); 03460 warned = TRUE; 03461 } 03462 03463 *( (DWORD *) dest_ptr) = 0xFF000000; 03464 dest_ptr += sizeof(DWORD); 03465 03466 if(dest_conv) { 03467 *( (DWORD *) dest_conv) = 0xFF000000; 03468 dest_conv += sizeof(DWORD); 03469 } 03470 } 03471 else { 03472 copy_and_next(dest_ptr, color_s, sizeof(DWORD)); 03473 if(dest_conv) { 03474 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */ 03475 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */ 03476 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */ 03477 dest_conv += sizeof(DWORD); 03478 } 03479 } 03480 } 03481 03482 for (tex_index = 0; tex_index < numTextures; ++tex_index) 03483 { 03484 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index]; 03485 const float *tex_coord = (const float *)(element->data.addr + i * element->stride); 03486 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index)))) 03487 { 03488 ERR("No source texture, but destination requests one\n"); 03489 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float); 03490 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float); 03491 } 03492 else { 03493 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float)); 03494 if(dest_conv) { 03495 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float)); 03496 } 03497 } 03498 } 03499 } 03500 03501 if (dest_conv) 03502 { 03503 ENTER_GL(); 03504 03505 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object)); 03506 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)"); 03507 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF), 03508 dwCount * get_flexible_vertex_size(DestFVF), 03509 dest_conv_addr)); 03510 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)"); 03511 03512 LEAVE_GL(); 03513 03514 HeapFree(GetProcessHeap(), 0, dest_conv_addr); 03515 } 03516 03517 return WINED3D_OK; 03518 } 03519 #undef copy_and_next 03520 03521 /* Do not call while under the GL lock. */ 03522 HRESULT CDECL wined3d_device_process_vertices(struct wined3d_device *device, 03523 UINT src_start_idx, UINT dst_idx, UINT vertex_count, struct wined3d_buffer *dst_buffer, 03524 const struct wined3d_vertex_declaration *declaration, DWORD flags, DWORD dst_fvf) 03525 { 03526 struct wined3d_state *state = &device->stateBlock->state; 03527 BOOL vbo = FALSE, streamWasUP = state->user_stream; 03528 struct wined3d_stream_info stream_info; 03529 const struct wined3d_gl_info *gl_info; 03530 struct wined3d_context *context; 03531 struct wined3d_shader *vs; 03532 HRESULT hr; 03533 03534 TRACE("device %p, src_start_idx %u, dst_idx %u, vertex_count %u, " 03535 "dst_buffer %p, declaration %p, flags %#x, dst_fvf %#x.\n", 03536 device, src_start_idx, dst_idx, vertex_count, 03537 dst_buffer, declaration, flags, dst_fvf); 03538 03539 if (declaration) 03540 FIXME("Output vertex declaration not implemented yet.\n"); 03541 03542 /* Need any context to write to the vbo. */ 03543 context = context_acquire(device, NULL); 03544 gl_info = context->gl_info; 03545 03546 /* ProcessVertices reads from vertex buffers, which have to be assigned. 03547 * DrawPrimitive and DrawPrimitiveUP control the streamIsUP flag, thus 03548 * restore it afterwards. */ 03549 vs = state->vertex_shader; 03550 state->vertex_shader = NULL; 03551 state->user_stream = FALSE; 03552 device_stream_info_from_declaration(device, &stream_info, &vbo); 03553 state->user_stream = streamWasUP; 03554 state->vertex_shader = vs; 03555 03556 if (vbo || src_start_idx) 03557 { 03558 unsigned int i; 03559 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are 03560 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure 03561 * 03562 * Also get the start index in, but only loop over all elements if there's something to add at all. 03563 */ 03564 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i) 03565 { 03566 struct wined3d_stream_info_element *e; 03567 03568 if (!(stream_info.use_map & (1 << i))) continue; 03569 03570 e = &stream_info.elements[i]; 03571 if (e->data.buffer_object) 03572 { 03573 struct wined3d_buffer *vb = state->streams[e->stream_idx].buffer; 03574 e->data.buffer_object = 0; 03575 e->data.addr = (BYTE *)((ULONG_PTR)e->data.addr + (ULONG_PTR)buffer_get_sysmem(vb, gl_info)); 03576 ENTER_GL(); 03577 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object)); 03578 vb->buffer_object = 0; 03579 LEAVE_GL(); 03580 } 03581 if (e->data.addr) 03582 e->data.addr += e->stride * src_start_idx; 03583 } 03584 } 03585 03586 hr = process_vertices_strided(device, dst_idx, vertex_count, 03587 &stream_info, dst_buffer, flags, dst_fvf); 03588 03589 context_release(context); 03590 03591 return hr; 03592 } 03593 03594 HRESULT CDECL wined3d_device_set_texture_stage_state(struct wined3d_device *device, 03595 UINT stage, enum wined3d_texture_stage_state state, DWORD value) 03596 { 03597 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 03598 DWORD old_value; 03599 03600 TRACE("device %p, stage %u, state %s, value %#x.\n", 03601 device, stage, debug_d3dtexturestate(state), value); 03602 03603 if (state > WINED3D_HIGHEST_TEXTURE_STATE) 03604 { 03605 WARN("Invalid state %#x passed.\n", state); 03606 return WINED3D_OK; 03607 } 03608 03609 if (stage >= gl_info->limits.texture_stages) 03610 { 03611 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n", 03612 stage, gl_info->limits.texture_stages - 1); 03613 return WINED3D_OK; 03614 } 03615 03616 old_value = device->updateStateBlock->state.texture_states[stage][state]; 03617 device->updateStateBlock->changed.textureState[stage] |= 1 << state; 03618 device->updateStateBlock->state.texture_states[stage][state] = value; 03619 03620 if (device->isRecordingState) 03621 { 03622 TRACE("Recording... not performing anything.\n"); 03623 return WINED3D_OK; 03624 } 03625 03626 /* Checked after the assignments to allow proper stateblock recording. */ 03627 if (old_value == value) 03628 { 03629 TRACE("Application is setting the old value over, nothing to do.\n"); 03630 return WINED3D_OK; 03631 } 03632 03633 if (stage > device->stateBlock->state.lowest_disabled_stage 03634 && device->StateTable[STATE_TEXTURESTAGE(0, state)].representative 03635 == STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP)) 03636 { 03637 /* Colorop change above lowest disabled stage? That won't change 03638 * anything in the GL setup. Changes in other states are important on 03639 * disabled stages too. */ 03640 return WINED3D_OK; 03641 } 03642 03643 if (state == WINED3D_TSS_COLOR_OP) 03644 { 03645 unsigned int i; 03646 03647 if (value == WINED3D_TOP_DISABLE && old_value != WINED3D_TOP_DISABLE) 03648 { 03649 /* Previously enabled stage disabled now. Make sure to dirtify 03650 * all enabled stages above stage, they have to be disabled. 03651 * 03652 * The current stage is dirtified below. */ 03653 for (i = stage + 1; i < device->stateBlock->state.lowest_disabled_stage; ++i) 03654 { 03655 TRACE("Additionally dirtifying stage %u.\n", i); 03656 device_invalidate_state(device, STATE_TEXTURESTAGE(i, WINED3D_TSS_COLOR_OP)); 03657 } 03658 device->stateBlock->state.lowest_disabled_stage = stage; 03659 TRACE("New lowest disabled: %u.\n", stage); 03660 } 03661 else if (value != WINED3D_TOP_DISABLE && old_value == WINED3D_TOP_DISABLE) 03662 { 03663 /* Previously disabled stage enabled. Stages above it may need 03664 * enabling. Stage must be lowest_disabled_stage here, if it's 03665 * bigger success is returned above, and stages below the lowest 03666 * disabled stage can't be enabled (because they are enabled 03667 * already). 03668 * 03669 * Again stage stage doesn't need to be dirtified here, it is 03670 * handled below. */ 03671 for (i = stage + 1; i < gl_info->limits.texture_stages; ++i) 03672 { 03673 if (device->updateStateBlock->state.texture_states[i][WINED3D_TSS_COLOR_OP] == WINED3D_TOP_DISABLE) 03674 break; 03675 TRACE("Additionally dirtifying stage %u due to enable.\n", i); 03676 device_invalidate_state(device, STATE_TEXTURESTAGE(i, WINED3D_TSS_COLOR_OP)); 03677 } 03678 device->stateBlock->state.lowest_disabled_stage = i; 03679 TRACE("New lowest disabled: %u.\n", i); 03680 } 03681 } 03682 03683 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, state)); 03684 03685 return WINED3D_OK; 03686 } 03687 03688 HRESULT CDECL wined3d_device_get_texture_stage_state(const struct wined3d_device *device, 03689 UINT stage, enum wined3d_texture_stage_state state, DWORD *value) 03690 { 03691 TRACE("device %p, stage %u, state %s, value %p.\n", 03692 device, stage, debug_d3dtexturestate(state), value); 03693 03694 if (state > WINED3D_HIGHEST_TEXTURE_STATE) 03695 { 03696 WARN("Invalid state %#x passed.\n", state); 03697 return WINED3D_OK; 03698 } 03699 03700 *value = device->updateStateBlock->state.texture_states[stage][state]; 03701 TRACE("Returning %#x.\n", *value); 03702 03703 return WINED3D_OK; 03704 } 03705 03706 HRESULT CDECL wined3d_device_set_texture(struct wined3d_device *device, 03707 UINT stage, struct wined3d_texture *texture) 03708 { 03709 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 03710 struct wined3d_texture *prev; 03711 03712 TRACE("device %p, stage %u, texture %p.\n", device, stage, texture); 03713 03714 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3) 03715 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS); 03716 03717 /* Windows accepts overflowing this array... we do not. */ 03718 if (stage >= sizeof(device->stateBlock->state.textures) / sizeof(*device->stateBlock->state.textures)) 03719 { 03720 WARN("Ignoring invalid stage %u.\n", stage); 03721 return WINED3D_OK; 03722 } 03723 03724 if (texture && texture->resource.pool == WINED3D_POOL_SCRATCH) 03725 { 03726 WARN("Rejecting attempt to set scratch texture.\n"); 03727 return WINED3DERR_INVALIDCALL; 03728 } 03729 03730 device->updateStateBlock->changed.textures |= 1 << stage; 03731 03732 prev = device->updateStateBlock->state.textures[stage]; 03733 TRACE("Previous texture %p.\n", prev); 03734 03735 if (texture == prev) 03736 { 03737 TRACE("App is setting the same texture again, nothing to do.\n"); 03738 return WINED3D_OK; 03739 } 03740 03741 TRACE("Setting new texture to %p.\n", texture); 03742 device->updateStateBlock->state.textures[stage] = texture; 03743 03744 if (device->isRecordingState) 03745 { 03746 TRACE("Recording... not performing anything\n"); 03747 03748 if (texture) wined3d_texture_incref(texture); 03749 if (prev) wined3d_texture_decref(prev); 03750 03751 return WINED3D_OK; 03752 } 03753 03754 if (texture) 03755 { 03756 LONG bind_count = InterlockedIncrement(&texture->bind_count); 03757 03758 wined3d_texture_incref(texture); 03759 03760 if (!prev || texture->target != prev->target) 03761 device_invalidate_state(device, STATE_PIXELSHADER); 03762 03763 if (!prev && stage < gl_info->limits.texture_stages) 03764 { 03765 /* The source arguments for color and alpha ops have different 03766 * meanings when a NULL texture is bound, so the COLOR_OP and 03767 * ALPHA_OP have to be dirtified. */ 03768 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_COLOR_OP)); 03769 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_ALPHA_OP)); 03770 } 03771 03772 if (bind_count == 1) 03773 texture->sampler = stage; 03774 } 03775 03776 if (prev) 03777 { 03778 LONG bind_count = InterlockedDecrement(&prev->bind_count); 03779 03780 wined3d_texture_decref(prev); 03781 03782 if (!texture && stage < gl_info->limits.texture_stages) 03783 { 03784 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_COLOR_OP)); 03785 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_ALPHA_OP)); 03786 } 03787 03788 if (bind_count && prev->sampler == stage) 03789 { 03790 unsigned int i; 03791 03792 /* Search for other stages the texture is bound to. Shouldn't 03793 * happen if applications bind textures to a single stage only. */ 03794 TRACE("Searching for other stages the texture is bound to.\n"); 03795 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i) 03796 { 03797 if (device->updateStateBlock->state.textures[i] == prev) 03798 { 03799 TRACE("Texture is also bound to stage %u.\n", i); 03800 prev->sampler = i; 03801 break; 03802 } 03803 } 03804 } 03805 } 03806 03807 device_invalidate_state(device, STATE_SAMPLER(stage)); 03808 03809 return WINED3D_OK; 03810 } 03811 03812 HRESULT CDECL wined3d_device_get_texture(const struct wined3d_device *device, 03813 UINT stage, struct wined3d_texture **texture) 03814 { 03815 TRACE("device %p, stage %u, texture %p.\n", device, stage, texture); 03816 03817 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3) 03818 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS); 03819 03820 if (stage >= sizeof(device->stateBlock->state.textures) / sizeof(*device->stateBlock->state.textures)) 03821 { 03822 WARN("Ignoring invalid stage %u.\n", stage); 03823 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */ 03824 } 03825 03826 *texture = device->stateBlock->state.textures[stage]; 03827 if (*texture) 03828 wined3d_texture_incref(*texture); 03829 03830 TRACE("Returning %p.\n", *texture); 03831 03832 return WINED3D_OK; 03833 } 03834 03835 HRESULT CDECL wined3d_device_get_back_buffer(const struct wined3d_device *device, UINT swapchain_idx, 03836 UINT backbuffer_idx, enum wined3d_backbuffer_type backbuffer_type, struct wined3d_surface **backbuffer) 03837 { 03838 struct wined3d_swapchain *swapchain; 03839 HRESULT hr; 03840 03841 TRACE("device %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n", 03842 device, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer); 03843 03844 hr = wined3d_device_get_swapchain(device, swapchain_idx, &swapchain); 03845 if (FAILED(hr)) 03846 { 03847 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr); 03848 return hr; 03849 } 03850 03851 hr = wined3d_swapchain_get_back_buffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer); 03852 wined3d_swapchain_decref(swapchain); 03853 if (FAILED(hr)) 03854 { 03855 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr); 03856 return hr; 03857 } 03858 03859 return WINED3D_OK; 03860 } 03861 03862 HRESULT CDECL wined3d_device_get_device_caps(const struct wined3d_device *device, WINED3DCAPS *caps) 03863 { 03864 TRACE("device %p, caps %p.\n", device, caps); 03865 03866 return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal, 03867 device->create_parms.device_type, caps); 03868 } 03869 03870 HRESULT CDECL wined3d_device_get_display_mode(const struct wined3d_device *device, 03871 UINT swapchain_idx, struct wined3d_display_mode *mode) 03872 { 03873 struct wined3d_swapchain *swapchain; 03874 HRESULT hr; 03875 03876 TRACE("device %p, swapchain_idx %u, mode %p.\n", device, swapchain_idx, mode); 03877 03878 if (swapchain_idx) 03879 { 03880 hr = wined3d_device_get_swapchain(device, swapchain_idx, &swapchain); 03881 if (SUCCEEDED(hr)) 03882 { 03883 hr = wined3d_swapchain_get_display_mode(swapchain, mode); 03884 wined3d_swapchain_decref(swapchain); 03885 } 03886 } 03887 else 03888 { 03889 const struct wined3d_adapter *adapter = device->adapter; 03890 03891 /* Don't read the real display mode, but return the stored mode 03892 * instead. X11 can't change the color depth, and some apps are 03893 * pretty angry if they SetDisplayMode from 24 to 16 bpp and find out 03894 * that GetDisplayMode still returns 24 bpp. 03895 * 03896 * Also don't relay to the swapchain because with ddraw it's possible 03897 * that there isn't a swapchain at all. */ 03898 mode->width = adapter->screen_size.cx; 03899 mode->height = adapter->screen_size.cy; 03900 mode->format_id = adapter->screen_format; 03901 mode->refresh_rate = 0; 03902 hr = WINED3D_OK; 03903 } 03904 03905 return hr; 03906 } 03907 03908 HRESULT CDECL wined3d_device_begin_stateblock(struct wined3d_device *device) 03909 { 03910 struct wined3d_stateblock *stateblock; 03911 HRESULT hr; 03912 03913 TRACE("device %p.\n", device); 03914 03915 if (device->isRecordingState) 03916 return WINED3DERR_INVALIDCALL; 03917 03918 hr = wined3d_stateblock_create(device, WINED3D_SBT_RECORDED, &stateblock); 03919 if (FAILED(hr)) 03920 return hr; 03921 03922 wined3d_stateblock_decref(device->updateStateBlock); 03923 device->updateStateBlock = stateblock; 03924 device->isRecordingState = TRUE; 03925 03926 TRACE("Recording stateblock %p.\n", stateblock); 03927 03928 return WINED3D_OK; 03929 } 03930 03931 HRESULT CDECL wined3d_device_end_stateblock(struct wined3d_device *device, 03932 struct wined3d_stateblock **stateblock) 03933 { 03934 struct wined3d_stateblock *object = device->updateStateBlock; 03935 03936 TRACE("device %p, stateblock %p.\n", device, stateblock); 03937 03938 if (!device->isRecordingState) 03939 { 03940 WARN("Not recording.\n"); 03941 *stateblock = NULL; 03942 return WINED3DERR_INVALIDCALL; 03943 } 03944 03945 stateblock_init_contained_states(object); 03946 03947 *stateblock = object; 03948 device->isRecordingState = FALSE; 03949 device->updateStateBlock = device->stateBlock; 03950 wined3d_stateblock_incref(device->updateStateBlock); 03951 03952 TRACE("Returning stateblock %p.\n", *stateblock); 03953 03954 return WINED3D_OK; 03955 } 03956 03957 HRESULT CDECL wined3d_device_begin_scene(struct wined3d_device *device) 03958 { 03959 /* At the moment we have no need for any functionality at the beginning 03960 * of a scene. */ 03961 TRACE("device %p.\n", device); 03962 03963 if (device->inScene) 03964 { 03965 WARN("Already in scene, returning WINED3DERR_INVALIDCALL.\n"); 03966 return WINED3DERR_INVALIDCALL; 03967 } 03968 device->inScene = TRUE; 03969 return WINED3D_OK; 03970 } 03971 03972 HRESULT CDECL wined3d_device_end_scene(struct wined3d_device *device) 03973 { 03974 struct wined3d_context *context; 03975 03976 TRACE("device %p.\n", device); 03977 03978 if (!device->inScene) 03979 { 03980 WARN("Not in scene, returning WINED3DERR_INVALIDCALL.\n"); 03981 return WINED3DERR_INVALIDCALL; 03982 } 03983 03984 context = context_acquire(device, NULL); 03985 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */ 03986 wglFlush(); 03987 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever 03988 * fails. */ 03989 context_release(context); 03990 03991 device->inScene = FALSE; 03992 return WINED3D_OK; 03993 } 03994 03995 HRESULT CDECL wined3d_device_present(const struct wined3d_device *device, const RECT *src_rect, 03996 const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region) 03997 { 03998 UINT i; 03999 04000 TRACE("device %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p.\n", 04001 device, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect), 04002 dst_window_override, dirty_region); 04003 04004 for (i = 0; i < device->swapchain_count; ++i) 04005 { 04006 wined3d_swapchain_present(device->swapchains[i], src_rect, 04007 dst_rect, dst_window_override, dirty_region, 0); 04008 } 04009 04010 return WINED3D_OK; 04011 } 04012 04013 /* Do not call while under the GL lock. */ 04014 HRESULT CDECL wined3d_device_clear(struct wined3d_device *device, DWORD rect_count, 04015 const RECT *rects, DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil) 04016 { 04017 RECT draw_rect; 04018 04019 TRACE("device %p, rect_count %u, rects %p, flags %#x, color {%.8e, %.8e, %.8e, %.8e}, depth %.8e, stencil %u.\n", 04020 device, rect_count, rects, flags, color->r, color->g, color->b, color->a, depth, stencil); 04021 04022 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) 04023 { 04024 struct wined3d_surface *ds = device->fb.depth_stencil; 04025 if (!ds) 04026 { 04027 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n"); 04028 /* TODO: What about depth stencil buffers without stencil bits? */ 04029 return WINED3DERR_INVALIDCALL; 04030 } 04031 else if (flags & WINED3DCLEAR_TARGET) 04032 { 04033 if (ds->resource.width < device->fb.render_targets[0]->resource.width 04034 || ds->resource.height < device->fb.render_targets[0]->resource.height) 04035 { 04036 WARN("Silently ignoring depth and target clear with mismatching sizes\n"); 04037 return WINED3D_OK; 04038 } 04039 } 04040 } 04041 04042 wined3d_get_draw_rect(&device->stateBlock->state, &draw_rect); 04043 04044 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers, 04045 &device->fb, rect_count, rects, 04046 &draw_rect, flags, color, depth, stencil); 04047 } 04048 04049 void CDECL wined3d_device_set_primitive_type(struct wined3d_device *device, 04050 enum wined3d_primitive_type primitive_type) 04051 { 04052 TRACE("device %p, primitive_type %s\n", device, debug_d3dprimitivetype(primitive_type)); 04053 04054 device->updateStateBlock->changed.primitive_type = TRUE; 04055 device->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type); 04056 } 04057 04058 void CDECL wined3d_device_get_primitive_type(const struct wined3d_device *device, 04059 enum wined3d_primitive_type *primitive_type) 04060 { 04061 TRACE("device %p, primitive_type %p\n", device, primitive_type); 04062 04063 *primitive_type = d3d_primitive_type_from_gl(device->stateBlock->state.gl_primitive_type); 04064 04065 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type)); 04066 } 04067 04068 HRESULT CDECL wined3d_device_draw_primitive(struct wined3d_device *device, UINT start_vertex, UINT vertex_count) 04069 { 04070 TRACE("device %p, start_vertex %u, vertex_count %u.\n", device, start_vertex, vertex_count); 04071 04072 if (!device->stateBlock->state.vertex_declaration) 04073 { 04074 WARN("Called without a valid vertex declaration set.\n"); 04075 return WINED3DERR_INVALIDCALL; 04076 } 04077 04078 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */ 04079 if (device->stateBlock->state.user_stream) 04080 { 04081 device_invalidate_state(device, STATE_INDEXBUFFER); 04082 device->stateBlock->state.user_stream = FALSE; 04083 } 04084 04085 if (device->stateBlock->state.load_base_vertex_index) 04086 { 04087 device->stateBlock->state.load_base_vertex_index = 0; 04088 device_invalidate_state(device, STATE_BASEVERTEXINDEX); 04089 } 04090 04091 /* Account for the loading offset due to index buffers. Instead of 04092 * reloading all sources correct it with the startvertex parameter. */ 04093 drawPrimitive(device, vertex_count, start_vertex, 0, NULL); 04094 return WINED3D_OK; 04095 } 04096 04097 HRESULT CDECL wined3d_device_draw_indexed_primitive(struct wined3d_device *device, UINT start_idx, UINT index_count) 04098 { 04099 struct wined3d_buffer *index_buffer; 04100 UINT index_size = 2; 04101 GLuint vbo; 04102 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 04103 04104 TRACE("device %p, start_idx %u, index_count %u.\n", device, start_idx, index_count); 04105 04106 index_buffer = device->stateBlock->state.index_buffer; 04107 if (!index_buffer) 04108 { 04109 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called 04110 * without an index buffer set. (The first time at least...) 04111 * D3D8 simply dies, but I doubt it can do much harm to return 04112 * D3DERR_INVALIDCALL there as well. */ 04113 WARN("Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL.\n"); 04114 return WINED3DERR_INVALIDCALL; 04115 } 04116 04117 if (!device->stateBlock->state.vertex_declaration) 04118 { 04119 WARN("Called without a valid vertex declaration set.\n"); 04120 return WINED3DERR_INVALIDCALL; 04121 } 04122 04123 if (device->stateBlock->state.user_stream) 04124 { 04125 device_invalidate_state(device, STATE_INDEXBUFFER); 04126 device->stateBlock->state.user_stream = FALSE; 04127 } 04128 vbo = index_buffer->buffer_object; 04129 04130 if (device->stateBlock->state.index_format == WINED3DFMT_R16_UINT) 04131 index_size = 2; 04132 else 04133 index_size = 4; 04134 04135 if (!gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX] && 04136 device->stateBlock->state.load_base_vertex_index != device->stateBlock->state.base_vertex_index) 04137 { 04138 device->stateBlock->state.load_base_vertex_index = device->stateBlock->state.base_vertex_index; 04139 device_invalidate_state(device, STATE_BASEVERTEXINDEX); 04140 } 04141 04142 drawPrimitive(device, index_count, start_idx, index_size, 04143 vbo ? NULL : index_buffer->resource.allocatedMemory); 04144 04145 return WINED3D_OK; 04146 } 04147 04148 HRESULT CDECL wined3d_device_draw_primitive_up(struct wined3d_device *device, UINT vertex_count, 04149 const void *stream_data, UINT stream_stride) 04150 { 04151 struct wined3d_stream_state *stream; 04152 struct wined3d_buffer *vb; 04153 04154 TRACE("device %p, vertex count %u, stream_data %p, stream_stride %u.\n", 04155 device, vertex_count, stream_data, stream_stride); 04156 04157 if (!device->stateBlock->state.vertex_declaration) 04158 { 04159 WARN("Called without a valid vertex declaration set.\n"); 04160 return WINED3DERR_INVALIDCALL; 04161 } 04162 04163 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */ 04164 stream = &device->stateBlock->state.streams[0]; 04165 vb = stream->buffer; 04166 stream->buffer = (struct wined3d_buffer *)stream_data; 04167 if (vb) 04168 wined3d_buffer_decref(vb); 04169 stream->offset = 0; 04170 stream->stride = stream_stride; 04171 device->stateBlock->state.user_stream = TRUE; 04172 if (device->stateBlock->state.load_base_vertex_index) 04173 { 04174 device->stateBlock->state.load_base_vertex_index = 0; 04175 device_invalidate_state(device, STATE_BASEVERTEXINDEX); 04176 } 04177 04178 /* TODO: Only mark dirty if drawing from a different UP address */ 04179 device_invalidate_state(device, STATE_STREAMSRC); 04180 04181 drawPrimitive(device, vertex_count, 0, 0, NULL); 04182 04183 /* MSDN specifies stream zero settings must be set to NULL */ 04184 stream->buffer = NULL; 04185 stream->stride = 0; 04186 04187 /* stream zero settings set to null at end, as per the msdn. No need to 04188 * mark dirty here, the app has to set the new stream sources or use UP 04189 * drawing again. */ 04190 return WINED3D_OK; 04191 } 04192 04193 HRESULT CDECL wined3d_device_draw_indexed_primitive_up(struct wined3d_device *device, 04194 UINT index_count, const void *index_data, enum wined3d_format_id index_data_format_id, 04195 const void *stream_data, UINT stream_stride) 04196 { 04197 struct wined3d_stream_state *stream; 04198 struct wined3d_buffer *vb, *ib; 04199 UINT index_size; 04200 04201 TRACE("device %p, index_count %u, index_data %p, index_data_format %s, stream_data %p, stream_stride %u.\n", 04202 device, index_count, index_data, debug_d3dformat(index_data_format_id), stream_data, stream_stride); 04203 04204 if (!device->stateBlock->state.vertex_declaration) 04205 { 04206 WARN("(%p) : Called without a valid vertex declaration set\n", device); 04207 return WINED3DERR_INVALIDCALL; 04208 } 04209 04210 if (index_data_format_id == WINED3DFMT_R16_UINT) 04211 index_size = 2; 04212 else 04213 index_size = 4; 04214 04215 stream = &device->stateBlock->state.streams[0]; 04216 vb = stream->buffer; 04217 stream->buffer = (struct wined3d_buffer *)stream_data; 04218 if (vb) 04219 wined3d_buffer_decref(vb); 04220 stream->offset = 0; 04221 stream->stride = stream_stride; 04222 device->stateBlock->state.user_stream = TRUE; 04223 04224 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */ 04225 device->stateBlock->state.base_vertex_index = 0; 04226 if (device->stateBlock->state.load_base_vertex_index) 04227 { 04228 device->stateBlock->state.load_base_vertex_index = 0; 04229 device_invalidate_state(device, STATE_BASEVERTEXINDEX); 04230 } 04231 /* Invalidate the state until we have nicer tracking of the stream source pointers */ 04232 device_invalidate_state(device, STATE_STREAMSRC); 04233 device_invalidate_state(device, STATE_INDEXBUFFER); 04234 04235 drawPrimitive(device, index_count, 0, index_size, index_data); 04236 04237 /* MSDN specifies stream zero settings and index buffer must be set to NULL */ 04238 stream->buffer = NULL; 04239 stream->stride = 0; 04240 ib = device->stateBlock->state.index_buffer; 04241 if (ib) 04242 { 04243 wined3d_buffer_decref(ib); 04244 device->stateBlock->state.index_buffer = NULL; 04245 } 04246 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call 04247 * SetStreamSource to specify a vertex buffer 04248 */ 04249 04250 return WINED3D_OK; 04251 } 04252 04253 HRESULT CDECL wined3d_device_draw_primitive_strided(struct wined3d_device *device, 04254 UINT vertex_count, const struct wined3d_strided_data *strided_data) 04255 { 04256 /* Mark the state dirty until we have nicer tracking. It's fine to change 04257 * baseVertexIndex because that call is only called by ddraw which does 04258 * not need that value. */ 04259 device_invalidate_state(device, STATE_VDECL); 04260 device_invalidate_state(device, STATE_STREAMSRC); 04261 device_invalidate_state(device, STATE_INDEXBUFFER); 04262 04263 device->stateBlock->state.base_vertex_index = 0; 04264 device->up_strided = strided_data; 04265 drawPrimitive(device, vertex_count, 0, 0, NULL); 04266 device->up_strided = NULL; 04267 04268 /* Invalidate the states again to make sure the values from the stateblock 04269 * are properly applied in the next regular draw. Note that the application- 04270 * provided strided data has ovwritten pretty much the entire vertex and 04271 * and index stream related states */ 04272 device_invalidate_state(device, STATE_VDECL); 04273 device_invalidate_state(device, STATE_STREAMSRC); 04274 device_invalidate_state(device, STATE_INDEXBUFFER); 04275 return WINED3D_OK; 04276 } 04277 04278 HRESULT CDECL wined3d_device_draw_indexed_primitive_strided(struct wined3d_device *device, 04279 UINT index_count, const struct wined3d_strided_data *strided_data, 04280 UINT vertex_count, const void *index_data, enum wined3d_format_id index_data_format_id) 04281 { 04282 UINT index_size = index_data_format_id == WINED3DFMT_R32_UINT ? 4 : 2; 04283 04284 /* Mark the state dirty until we have nicer tracking 04285 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need 04286 * that value. 04287 */ 04288 device_invalidate_state(device, STATE_VDECL); 04289 device_invalidate_state(device, STATE_STREAMSRC); 04290 device_invalidate_state(device, STATE_INDEXBUFFER); 04291 04292 device->stateBlock->state.user_stream = TRUE; 04293 device->stateBlock->state.base_vertex_index = 0; 04294 device->up_strided = strided_data; 04295 drawPrimitive(device, index_count, 0, index_size, index_data); 04296 device->up_strided = NULL; 04297 04298 device_invalidate_state(device, STATE_VDECL); 04299 device_invalidate_state(device, STATE_STREAMSRC); 04300 device_invalidate_state(device, STATE_INDEXBUFFER); 04301 return WINED3D_OK; 04302 } 04303 04304 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */ 04305 static HRESULT device_update_volume(struct wined3d_device *device, 04306 struct wined3d_volume *src_volume, struct wined3d_volume *dst_volume) 04307 { 04308 struct wined3d_mapped_box src; 04309 struct wined3d_mapped_box dst; 04310 HRESULT hr; 04311 04312 TRACE("device %p, src_volume %p, dst_volume %p.\n", 04313 device, src_volume, dst_volume); 04314 04315 /* TODO: Implement direct loading into the gl volume instead of using 04316 * memcpy and dirtification to improve loading performance. */ 04317 hr = wined3d_volume_map(src_volume, &src, NULL, WINED3DLOCK_READONLY); 04318 if (FAILED(hr)) return hr; 04319 hr = wined3d_volume_map(dst_volume, &dst, NULL, WINED3DLOCK_DISCARD); 04320 if (FAILED(hr)) 04321 { 04322 wined3d_volume_unmap(src_volume); 04323 return hr; 04324 } 04325 04326 memcpy(dst.data, src.data, dst_volume->resource.size); 04327 04328 hr = wined3d_volume_unmap(dst_volume); 04329 if (FAILED(hr)) 04330 wined3d_volume_unmap(src_volume); 04331 else 04332 hr = wined3d_volume_unmap(src_volume); 04333 04334 return hr; 04335 } 04336 04337 HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device, 04338 struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture) 04339 { 04340 enum wined3d_resource_type type; 04341 unsigned int level_count, i; 04342 HRESULT hr; 04343 04344 TRACE("device %p, src_texture %p, dst_texture %p.\n", device, src_texture, dst_texture); 04345 04346 /* Verify that the source and destination textures are non-NULL. */ 04347 if (!src_texture || !dst_texture) 04348 { 04349 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n"); 04350 return WINED3DERR_INVALIDCALL; 04351 } 04352 04353 if (src_texture == dst_texture) 04354 { 04355 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n"); 04356 return WINED3DERR_INVALIDCALL; 04357 } 04358 04359 /* Verify that the source and destination textures are the same type. */ 04360 type = src_texture->resource.type; 04361 if (dst_texture->resource.type != type) 04362 { 04363 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n"); 04364 return WINED3DERR_INVALIDCALL; 04365 } 04366 04367 /* Check that both textures have the identical numbers of levels. */ 04368 level_count = wined3d_texture_get_level_count(src_texture); 04369 if (wined3d_texture_get_level_count(dst_texture) != level_count) 04370 { 04371 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n"); 04372 return WINED3DERR_INVALIDCALL; 04373 } 04374 04375 /* Make sure that the destination texture is loaded. */ 04376 dst_texture->texture_ops->texture_preload(dst_texture, SRGB_RGB); 04377 04378 /* Update every surface level of the texture. */ 04379 switch (type) 04380 { 04381 case WINED3D_RTYPE_TEXTURE: 04382 { 04383 struct wined3d_surface *src_surface; 04384 struct wined3d_surface *dst_surface; 04385 04386 for (i = 0; i < level_count; ++i) 04387 { 04388 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i)); 04389 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i)); 04390 hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL); 04391 if (FAILED(hr)) 04392 { 04393 WARN("Failed to update surface, hr %#x.\n", hr); 04394 return hr; 04395 } 04396 } 04397 break; 04398 } 04399 04400 case WINED3D_RTYPE_CUBE_TEXTURE: 04401 { 04402 struct wined3d_surface *src_surface; 04403 struct wined3d_surface *dst_surface; 04404 04405 for (i = 0; i < level_count * 6; ++i) 04406 { 04407 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i)); 04408 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i)); 04409 hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL); 04410 if (FAILED(hr)) 04411 { 04412 WARN("Failed to update surface, hr %#x.\n", hr); 04413 return hr; 04414 } 04415 } 04416 break; 04417 } 04418 04419 case WINED3D_RTYPE_VOLUME_TEXTURE: 04420 { 04421 for (i = 0; i < level_count; ++i) 04422 { 04423 hr = device_update_volume(device, 04424 volume_from_resource(wined3d_texture_get_sub_resource(src_texture, i)), 04425 volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i))); 04426 if (FAILED(hr)) 04427 { 04428 WARN("Failed to update volume, hr %#x.\n", hr); 04429 return hr; 04430 } 04431 } 04432 break; 04433 } 04434 04435 default: 04436 FIXME("Unsupported texture type %#x.\n", type); 04437 return WINED3DERR_INVALIDCALL; 04438 } 04439 04440 return WINED3D_OK; 04441 } 04442 04443 HRESULT CDECL wined3d_device_get_front_buffer_data(const struct wined3d_device *device, 04444 UINT swapchain_idx, struct wined3d_surface *dst_surface) 04445 { 04446 struct wined3d_swapchain *swapchain; 04447 HRESULT hr; 04448 04449 TRACE("device %p, swapchain_idx %u, dst_surface %p.\n", device, swapchain_idx, dst_surface); 04450 04451 hr = wined3d_device_get_swapchain(device, swapchain_idx, &swapchain); 04452 if (FAILED(hr)) return hr; 04453 04454 hr = wined3d_swapchain_get_front_buffer_data(swapchain, dst_surface); 04455 wined3d_swapchain_decref(swapchain); 04456 04457 return hr; 04458 } 04459 04460 HRESULT CDECL wined3d_device_validate_device(const struct wined3d_device *device, DWORD *num_passes) 04461 { 04462 const struct wined3d_state *state = &device->stateBlock->state; 04463 struct wined3d_texture *texture; 04464 DWORD i; 04465 04466 TRACE("device %p, num_passes %p.\n", device, num_passes); 04467 04468 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i) 04469 { 04470 if (state->sampler_states[i][WINED3D_SAMP_MIN_FILTER] == WINED3D_TEXF_NONE) 04471 { 04472 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i); 04473 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER; 04474 } 04475 if (state->sampler_states[i][WINED3D_SAMP_MAG_FILTER] == WINED3D_TEXF_NONE) 04476 { 04477 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i); 04478 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER; 04479 } 04480 04481 texture = state->textures[i]; 04482 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue; 04483 04484 if (state->sampler_states[i][WINED3D_SAMP_MAG_FILTER] != WINED3D_TEXF_POINT) 04485 { 04486 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i); 04487 return E_FAIL; 04488 } 04489 if (state->sampler_states[i][WINED3D_SAMP_MIN_FILTER] != WINED3D_TEXF_POINT) 04490 { 04491 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i); 04492 return E_FAIL; 04493 } 04494 if (state->sampler_states[i][WINED3D_SAMP_MIP_FILTER] != WINED3D_TEXF_NONE 04495 && state->sampler_states[i][WINED3D_SAMP_MIP_FILTER] != WINED3D_TEXF_POINT) 04496 { 04497 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i); 04498 return E_FAIL; 04499 } 04500 } 04501 04502 if (state->render_states[WINED3D_RS_ZENABLE] || state->render_states[WINED3D_RS_ZWRITEENABLE] 04503 || state->render_states[WINED3D_RS_STENCILENABLE]) 04504 { 04505 struct wined3d_surface *ds = device->fb.depth_stencil; 04506 struct wined3d_surface *target = device->fb.render_targets[0]; 04507 04508 if(ds && target 04509 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height)) 04510 { 04511 WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n"); 04512 return WINED3DERR_CONFLICTINGRENDERSTATE; 04513 } 04514 } 04515 04516 /* return a sensible default */ 04517 *num_passes = 1; 04518 04519 TRACE("returning D3D_OK\n"); 04520 return WINED3D_OK; 04521 } 04522 04523 HRESULT CDECL wined3d_device_set_software_vertex_processing(struct wined3d_device *device, BOOL software) 04524 { 04525 static BOOL warned; 04526 04527 TRACE("device %p, software %#x.\n", device, software); 04528 04529 if (!warned) 04530 { 04531 FIXME("device %p, software %#x stub!\n", device, software); 04532 warned = TRUE; 04533 } 04534 04535 device->softwareVertexProcessing = software; 04536 04537 return WINED3D_OK; 04538 } 04539 04540 BOOL CDECL wined3d_device_get_software_vertex_processing(const struct wined3d_device *device) 04541 { 04542 static BOOL warned; 04543 04544 TRACE("device %p.\n", device); 04545 04546 if (!warned) 04547 { 04548 TRACE("device %p stub!\n", device); 04549 warned = TRUE; 04550 } 04551 04552 return device->softwareVertexProcessing; 04553 } 04554 04555 HRESULT CDECL wined3d_device_get_raster_status(const struct wined3d_device *device, 04556 UINT swapchain_idx, struct wined3d_raster_status *raster_status) 04557 { 04558 struct wined3d_swapchain *swapchain; 04559 HRESULT hr; 04560 04561 TRACE("device %p, swapchain_idx %u, raster_status %p.\n", 04562 device, swapchain_idx, raster_status); 04563 04564 hr = wined3d_device_get_swapchain(device, swapchain_idx, &swapchain); 04565 if (FAILED(hr)) 04566 { 04567 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr); 04568 return hr; 04569 } 04570 04571 hr = wined3d_swapchain_get_raster_status(swapchain, raster_status); 04572 wined3d_swapchain_decref(swapchain); 04573 if (FAILED(hr)) 04574 { 04575 WARN("Failed to get raster status, hr %#x.\n", hr); 04576 return hr; 04577 } 04578 04579 return WINED3D_OK; 04580 } 04581 04582 HRESULT CDECL wined3d_device_set_npatch_mode(struct wined3d_device *device, float segments) 04583 { 04584 static BOOL warned; 04585 04586 TRACE("device %p, segments %.8e.\n", device, segments); 04587 04588 if (segments != 0.0f) 04589 { 04590 if (!warned) 04591 { 04592 FIXME("device %p, segments %.8e stub!\n", device, segments); 04593 warned = TRUE; 04594 } 04595 } 04596 04597 return WINED3D_OK; 04598 } 04599 04600 float CDECL wined3d_device_get_npatch_mode(const struct wined3d_device *device) 04601 { 04602 static BOOL warned; 04603 04604 TRACE("device %p.\n", device); 04605 04606 if (!warned) 04607 { 04608 FIXME("device %p stub!\n", device); 04609 warned = TRUE; 04610 } 04611 04612 return 0.0f; 04613 } 04614 04615 HRESULT CDECL wined3d_device_update_surface(struct wined3d_device *device, 04616 struct wined3d_surface *src_surface, const RECT *src_rect, 04617 struct wined3d_surface *dst_surface, const POINT *dst_point) 04618 { 04619 TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n", 04620 device, src_surface, wine_dbgstr_rect(src_rect), 04621 dst_surface, wine_dbgstr_point(dst_point)); 04622 04623 if (src_surface->resource.pool != WINED3D_POOL_SYSTEM_MEM || dst_surface->resource.pool != WINED3D_POOL_DEFAULT) 04624 { 04625 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", 04626 src_surface, dst_surface); 04627 return WINED3DERR_INVALIDCALL; 04628 } 04629 04630 return surface_upload_from_surface(dst_surface, dst_point, src_surface, src_rect); 04631 } 04632 04633 HRESULT CDECL wined3d_device_draw_rect_patch(struct wined3d_device *device, UINT handle, 04634 const float *num_segs, const struct wined3d_rect_patch_info *rect_patch_info) 04635 { 04636 struct WineD3DRectPatch *patch; 04637 GLenum old_primitive_type; 04638 unsigned int i; 04639 struct list *e; 04640 BOOL found; 04641 04642 TRACE("device %p, handle %#x, num_segs %p, rect_patch_info %p.\n", 04643 device, handle, num_segs, rect_patch_info); 04644 04645 if (!(handle || rect_patch_info)) 04646 { 04647 /* TODO: Write a test for the return value, thus the FIXME */ 04648 FIXME("Both handle and rect_patch_info are NULL.\n"); 04649 return WINED3DERR_INVALIDCALL; 04650 } 04651 04652 if (handle) 04653 { 04654 i = PATCHMAP_HASHFUNC(handle); 04655 found = FALSE; 04656 LIST_FOR_EACH(e, &device->patches[i]) 04657 { 04658 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry); 04659 if (patch->Handle == handle) 04660 { 04661 found = TRUE; 04662 break; 04663 } 04664 } 04665 04666 if (!found) 04667 { 04668 TRACE("Patch does not exist. Creating a new one\n"); 04669 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch)); 04670 patch->Handle = handle; 04671 list_add_head(&device->patches[i], &patch->entry); 04672 } else { 04673 TRACE("Found existing patch %p\n", patch); 04674 } 04675 } 04676 else 04677 { 04678 /* Since opengl does not load tesselated vertex attributes into numbered vertex 04679 * attributes we have to tesselate, read back, and draw. This needs a patch 04680 * management structure instance. Create one. 04681 * 04682 * A possible improvement is to check if a vertex shader is used, and if not directly 04683 * draw the patch. 04684 */ 04685 FIXME("Drawing an uncached patch. This is slow\n"); 04686 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch)); 04687 } 04688 04689 if (num_segs[0] != patch->numSegs[0] || num_segs[1] != patch->numSegs[1] 04690 || num_segs[2] != patch->numSegs[2] || num_segs[3] != patch->numSegs[3] 04691 || (rect_patch_info && memcmp(rect_patch_info, &patch->rect_patch_info, sizeof(*rect_patch_info)))) 04692 { 04693 HRESULT hr; 04694 TRACE("Tesselation density or patch info changed, retesselating\n"); 04695 04696 if (rect_patch_info) 04697 patch->rect_patch_info = *rect_patch_info; 04698 04699 patch->numSegs[0] = num_segs[0]; 04700 patch->numSegs[1] = num_segs[1]; 04701 patch->numSegs[2] = num_segs[2]; 04702 patch->numSegs[3] = num_segs[3]; 04703 04704 hr = tesselate_rectpatch(device, patch); 04705 if (FAILED(hr)) 04706 { 04707 WARN("Patch tesselation failed.\n"); 04708 04709 /* Do not release the handle to store the params of the patch */ 04710 if (!handle) 04711 HeapFree(GetProcessHeap(), 0, patch); 04712 04713 return hr; 04714 } 04715 } 04716 04717 old_primitive_type = device->stateBlock->state.gl_primitive_type; 04718 device->stateBlock->state.gl_primitive_type = GL_TRIANGLES; 04719 wined3d_device_draw_primitive_strided(device, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided); 04720 device->stateBlock->state.gl_primitive_type = old_primitive_type; 04721 04722 /* Destroy uncached patches */ 04723 if (!handle) 04724 { 04725 HeapFree(GetProcessHeap(), 0, patch->mem); 04726 HeapFree(GetProcessHeap(), 0, patch); 04727 } 04728 return WINED3D_OK; 04729 } 04730 04731 HRESULT CDECL wined3d_device_draw_tri_patch(struct wined3d_device *device, UINT handle, 04732 const float *segment_count, const struct wined3d_tri_patch_info *patch_info) 04733 { 04734 FIXME("device %p, handle %#x, segment_count %p, patch_info %p stub!\n", 04735 device, handle, segment_count, patch_info); 04736 04737 return WINED3D_OK; 04738 } 04739 04740 HRESULT CDECL wined3d_device_delete_patch(struct wined3d_device *device, UINT handle) 04741 { 04742 struct WineD3DRectPatch *patch; 04743 struct list *e; 04744 int i; 04745 04746 TRACE("device %p, handle %#x.\n", device, handle); 04747 04748 i = PATCHMAP_HASHFUNC(handle); 04749 LIST_FOR_EACH(e, &device->patches[i]) 04750 { 04751 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry); 04752 if (patch->Handle == handle) 04753 { 04754 TRACE("Deleting patch %p\n", patch); 04755 list_remove(&patch->entry); 04756 HeapFree(GetProcessHeap(), 0, patch->mem); 04757 HeapFree(GetProcessHeap(), 0, patch); 04758 return WINED3D_OK; 04759 } 04760 } 04761 04762 /* TODO: Write a test for the return value */ 04763 FIXME("Attempt to destroy nonexistent patch\n"); 04764 return WINED3DERR_INVALIDCALL; 04765 } 04766 04767 /* Do not call while under the GL lock. */ 04768 HRESULT CDECL wined3d_device_color_fill(struct wined3d_device *device, 04769 struct wined3d_surface *surface, const RECT *rect, const struct wined3d_color *color) 04770 { 04771 RECT r; 04772 04773 TRACE("device %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n", 04774 device, surface, wine_dbgstr_rect(rect), 04775 color->r, color->g, color->b, color->a); 04776 04777 if (surface->resource.pool != WINED3D_POOL_DEFAULT && surface->resource.pool != WINED3D_POOL_SYSTEM_MEM) 04778 { 04779 WARN("Color-fill not allowed on %s surfaces.\n", debug_d3dpool(surface->resource.pool)); 04780 return WINED3DERR_INVALIDCALL; 04781 } 04782 04783 if (!rect) 04784 { 04785 SetRect(&r, 0, 0, surface->resource.width, surface->resource.height); 04786 rect = &r; 04787 } 04788 04789 return surface_color_fill(surface, rect, color); 04790 } 04791 04792 /* Do not call while under the GL lock. */ 04793 void CDECL wined3d_device_clear_rendertarget_view(struct wined3d_device *device, 04794 struct wined3d_rendertarget_view *rendertarget_view, const struct wined3d_color *color) 04795 { 04796 struct wined3d_resource *resource; 04797 HRESULT hr; 04798 RECT rect; 04799 04800 resource = rendertarget_view->resource; 04801 if (resource->type != WINED3D_RTYPE_SURFACE) 04802 { 04803 FIXME("Only supported on surface resources\n"); 04804 return; 04805 } 04806 04807 SetRect(&rect, 0, 0, resource->width, resource->height); 04808 hr = surface_color_fill(surface_from_resource(resource), &rect, color); 04809 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr); 04810 } 04811 04812 HRESULT CDECL wined3d_device_get_render_target(const struct wined3d_device *device, 04813 UINT render_target_idx, struct wined3d_surface **render_target) 04814 { 04815 TRACE("device %p, render_target_idx %u, render_target %p.\n", 04816 device, render_target_idx, render_target); 04817 04818 if (render_target_idx >= device->adapter->gl_info.limits.buffers) 04819 { 04820 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers); 04821 return WINED3DERR_INVALIDCALL; 04822 } 04823 04824 *render_target = device->fb.render_targets[render_target_idx]; 04825 TRACE("Returning render target %p.\n", *render_target); 04826 04827 if (!*render_target) 04828 return WINED3DERR_NOTFOUND; 04829 04830 wined3d_surface_incref(*render_target); 04831 04832 return WINED3D_OK; 04833 } 04834 04835 HRESULT CDECL wined3d_device_get_depth_stencil(const struct wined3d_device *device, 04836 struct wined3d_surface **depth_stencil) 04837 { 04838 TRACE("device %p, depth_stencil %p.\n", device, depth_stencil); 04839 04840 *depth_stencil = device->fb.depth_stencil; 04841 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil); 04842 04843 if (!*depth_stencil) 04844 return WINED3DERR_NOTFOUND; 04845 04846 wined3d_surface_incref(*depth_stencil); 04847 04848 return WINED3D_OK; 04849 } 04850 04851 HRESULT CDECL wined3d_device_set_render_target(struct wined3d_device *device, 04852 UINT render_target_idx, struct wined3d_surface *render_target, BOOL set_viewport) 04853 { 04854 struct wined3d_surface *prev; 04855 04856 TRACE("device %p, render_target_idx %u, render_target %p, set_viewport %#x.\n", 04857 device, render_target_idx, render_target, set_viewport); 04858 04859 if (render_target_idx >= device->adapter->gl_info.limits.buffers) 04860 { 04861 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers); 04862 return WINED3DERR_INVALIDCALL; 04863 } 04864 04865 prev = device->fb.render_targets[render_target_idx]; 04866 if (render_target == prev) 04867 { 04868 TRACE("Trying to do a NOP SetRenderTarget operation.\n"); 04869 return WINED3D_OK; 04870 } 04871 04872 /* Render target 0 can't be set to NULL. */ 04873 if (!render_target && !render_target_idx) 04874 { 04875 WARN("Trying to set render target 0 to NULL.\n"); 04876 return WINED3DERR_INVALIDCALL; 04877 } 04878 04879 if (render_target && !(render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)) 04880 { 04881 FIXME("Surface %p doesn't have render target usage.\n", render_target); 04882 return WINED3DERR_INVALIDCALL; 04883 } 04884 04885 if (render_target) 04886 wined3d_surface_incref(render_target); 04887 device->fb.render_targets[render_target_idx] = render_target; 04888 /* Release after the assignment, to prevent device_resource_released() 04889 * from seeing the surface as still in use. */ 04890 if (prev) 04891 wined3d_surface_decref(prev); 04892 04893 /* Render target 0 is special. */ 04894 if (!render_target_idx && set_viewport) 04895 { 04896 /* Set the viewport and scissor rectangles, if requested. Tests show 04897 * that stateblock recording is ignored, the change goes directly 04898 * into the primary stateblock. */ 04899 device->stateBlock->state.viewport.height = device->fb.render_targets[0]->resource.height; 04900 device->stateBlock->state.viewport.width = device->fb.render_targets[0]->resource.width; 04901 device->stateBlock->state.viewport.x = 0; 04902 device->stateBlock->state.viewport.y = 0; 04903 device->stateBlock->state.viewport.max_z = 1.0f; 04904 device->stateBlock->state.viewport.min_z = 0.0f; 04905 device_invalidate_state(device, STATE_VIEWPORT); 04906 04907 device->stateBlock->state.scissor_rect.top = 0; 04908 device->stateBlock->state.scissor_rect.left = 0; 04909 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.width; 04910 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.height; 04911 device_invalidate_state(device, STATE_SCISSORRECT); 04912 } 04913 04914 device_invalidate_state(device, STATE_FRAMEBUFFER); 04915 04916 return WINED3D_OK; 04917 } 04918 04919 HRESULT CDECL wined3d_device_set_depth_stencil(struct wined3d_device *device, struct wined3d_surface *depth_stencil) 04920 { 04921 struct wined3d_surface *prev = device->fb.depth_stencil; 04922 04923 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", 04924 device, depth_stencil, prev); 04925 04926 if (prev == depth_stencil) 04927 { 04928 TRACE("Trying to do a NOP SetRenderTarget operation.\n"); 04929 return WINED3D_OK; 04930 } 04931 04932 if (prev) 04933 { 04934 if (device->swapchains[0]->desc.flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL 04935 || prev->flags & SFLAG_DISCARD) 04936 { 04937 surface_modify_ds_location(prev, SFLAG_LOST, 04938 prev->resource.width, prev->resource.height); 04939 if (prev == device->onscreen_depth_stencil) 04940 { 04941 wined3d_surface_decref(device->onscreen_depth_stencil); 04942 device->onscreen_depth_stencil = NULL; 04943 } 04944 } 04945 } 04946 04947 device->fb.depth_stencil = depth_stencil; 04948 if (depth_stencil) 04949 wined3d_surface_incref(depth_stencil); 04950 04951 if (!prev != !depth_stencil) 04952 { 04953 /* Swapping NULL / non NULL depth stencil affects the depth and tests */ 04954 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_ZENABLE)); 04955 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILENABLE)); 04956 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK)); 04957 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS)); 04958 } 04959 else if (prev && prev->resource.format->depth_size != depth_stencil->resource.format->depth_size) 04960 { 04961 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS)); 04962 } 04963 if (prev) 04964 wined3d_surface_decref(prev); 04965 04966 device_invalidate_state(device, STATE_FRAMEBUFFER); 04967 04968 return WINED3D_OK; 04969 } 04970 04971 HRESULT CDECL wined3d_device_set_cursor_properties(struct wined3d_device *device, 04972 UINT x_hotspot, UINT y_hotspot, struct wined3d_surface *cursor_image) 04973 { 04974 struct wined3d_mapped_rect mapped_rect; 04975 04976 TRACE("device %p, x_hotspot %u, y_hotspot %u, cursor_image %p.\n", 04977 device, x_hotspot, y_hotspot, cursor_image); 04978 04979 /* some basic validation checks */ 04980 if (device->cursorTexture) 04981 { 04982 struct wined3d_context *context = context_acquire(device, NULL); 04983 ENTER_GL(); 04984 glDeleteTextures(1, &device->cursorTexture); 04985 LEAVE_GL(); 04986 context_release(context); 04987 device->cursorTexture = 0; 04988 } 04989 04990 if (cursor_image) 04991 { 04992 struct wined3d_mapped_rect rect; 04993 04994 /* MSDN: Cursor must be A8R8G8B8 */ 04995 if (cursor_image->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM) 04996 { 04997 WARN("surface %p has an invalid format.\n", cursor_image); 04998 return WINED3DERR_INVALIDCALL; 04999 } 05000 05001 /* MSDN: Cursor must be smaller than the display mode */ 05002 if (cursor_image->resource.width > device->adapter->screen_size.cx 05003 || cursor_image->resource.height > device->adapter->screen_size.cy) 05004 { 05005 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n", 05006 cursor_image, cursor_image->resource.width, cursor_image->resource.height, 05007 device->adapter->screen_size.cx, device->adapter->screen_size.cy); 05008 return WINED3DERR_INVALIDCALL; 05009 } 05010 05011 /* TODO: MSDN: Cursor sizes must be a power of 2 */ 05012 05013 /* Do not store the surface's pointer because the application may 05014 * release it after setting the cursor image. Windows doesn't 05015 * addref the set surface, so we can't do this either without 05016 * creating circular refcount dependencies. Copy out the gl texture 05017 * instead. */ 05018 device->cursorWidth = cursor_image->resource.width; 05019 device->cursorHeight = cursor_image->resource.height; 05020 if (SUCCEEDED(wined3d_surface_map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY))) 05021 { 05022 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; 05023 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM); 05024 struct wined3d_context *context; 05025 char *mem, *bits = rect.data; 05026 GLint intfmt = format->glInternal; 05027 GLint gl_format = format->glFormat; 05028 GLint type = format->glType; 05029 INT height = device->cursorHeight; 05030 INT width = device->cursorWidth; 05031 INT bpp = format->byte_count; 05032 INT i; 05033 05034 /* Reformat the texture memory (pitch and width can be 05035 * different) */ 05036 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp); 05037 for(i = 0; i < height; i++) 05038 memcpy(&mem[width * bpp * i], &bits[rect.row_pitch * i], width * bpp); 05039 wined3d_surface_unmap(cursor_image); 05040 05041 context = context_acquire(device, NULL); 05042 05043 ENTER_GL(); 05044 05045 if (gl_info->supported[APPLE_CLIENT_STORAGE]) 05046 { 05047 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); 05048 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)"); 05049 } 05050 05051 invalidate_active_texture(device, context); 05052 /* Create a new cursor texture */ 05053 glGenTextures(1, &device->cursorTexture); 05054 checkGLcall("glGenTextures"); 05055 context_bind_texture(context, GL_TEXTURE_2D, device->cursorTexture); 05056 /* Copy the bitmap memory into the cursor texture */ 05057 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem); 05058 checkGLcall("glTexImage2D"); 05059 HeapFree(GetProcessHeap(), 0, mem); 05060 05061 if (gl_info->supported[APPLE_CLIENT_STORAGE]) 05062 { 05063 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); 05064 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)"); 05065 } 05066 05067 LEAVE_GL(); 05068 05069 context_release(context); 05070 } 05071 else 05072 { 05073 FIXME("A cursor texture was not returned.\n"); 05074 device->cursorTexture = 0; 05075 } 05076 05077 if (cursor_image->resource.width == 32 && cursor_image->resource.height == 32) 05078 { 05079 /* Draw a hardware cursor */ 05080 ICONINFO cursorInfo; 05081 HCURSOR cursor; 05082 /* Create and clear maskBits because it is not needed for 05083 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32 05084 * chunks. */ 05085 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 05086 (cursor_image->resource.width * cursor_image->resource.height / 8)); 05087 wined3d_surface_map(cursor_image, &mapped_rect, NULL, 05088 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY); 05089 TRACE("width: %u height: %u.\n", cursor_image->resource.width, cursor_image->resource.height); 05090 05091 cursorInfo.fIcon = FALSE; 05092 cursorInfo.xHotspot = x_hotspot; 05093 cursorInfo.yHotspot = y_hotspot; 05094 cursorInfo.hbmMask = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height, 05095 1, 1, maskBits); 05096 cursorInfo.hbmColor = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height, 05097 1, 32, mapped_rect.data); 05098 wined3d_surface_unmap(cursor_image); 05099 /* Create our cursor and clean up. */ 05100 cursor = CreateIconIndirect(&cursorInfo); 05101 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask); 05102 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor); 05103 if (device->hardwareCursor) DestroyCursor(device->hardwareCursor); 05104 device->hardwareCursor = cursor; 05105 if (device->bCursorVisible) SetCursor( cursor ); 05106 HeapFree(GetProcessHeap(), 0, maskBits); 05107 } 05108 } 05109 05110 device->xHotSpot = x_hotspot; 05111 device->yHotSpot = y_hotspot; 05112 return WINED3D_OK; 05113 } 05114 05115 void CDECL wined3d_device_set_cursor_position(struct wined3d_device *device, 05116 int x_screen_space, int y_screen_space, DWORD flags) 05117 { 05118 TRACE("device %p, x %d, y %d, flags %#x.\n", 05119 device, x_screen_space, y_screen_space, flags); 05120 05121 device->xScreenSpace = x_screen_space; 05122 device->yScreenSpace = y_screen_space; 05123 05124 if (device->hardwareCursor) 05125 { 05126 POINT pt; 05127 05128 GetCursorPos( &pt ); 05129 if (x_screen_space == pt.x && y_screen_space == pt.y) 05130 return; 05131 SetCursorPos( x_screen_space, y_screen_space ); 05132 05133 /* Switch to the software cursor if position diverges from the hardware one. */ 05134 GetCursorPos( &pt ); 05135 if (x_screen_space != pt.x || y_screen_space != pt.y) 05136 { 05137 if (device->bCursorVisible) SetCursor( NULL ); 05138 DestroyCursor( device->hardwareCursor ); 05139 device->hardwareCursor = 0; 05140 } 05141 } 05142 } 05143 05144 BOOL CDECL wined3d_device_show_cursor(struct wined3d_device *device, BOOL show) 05145 { 05146 BOOL oldVisible = device->bCursorVisible; 05147 05148 TRACE("device %p, show %#x.\n", device, show); 05149 05150 /* 05151 * When ShowCursor is first called it should make the cursor appear at the OS's last 05152 * known cursor position. 05153 */ 05154 if (show && !oldVisible) 05155 { 05156 POINT pt; 05157 GetCursorPos(&pt); 05158 device->xScreenSpace = pt.x; 05159 device->yScreenSpace = pt.y; 05160 } 05161 05162 if (device->hardwareCursor) 05163 { 05164 device->bCursorVisible = show; 05165 if (show) 05166 SetCursor(device->hardwareCursor); 05167 else 05168 SetCursor(NULL); 05169 } 05170 else 05171 { 05172 if (device->cursorTexture) 05173 device->bCursorVisible = show; 05174 } 05175 05176 return oldVisible; 05177 } 05178 05179 void CDECL wined3d_device_evict_managed_resources(struct wined3d_device *device) 05180 { 05181 struct wined3d_resource *resource, *cursor; 05182 05183 TRACE("device %p.\n", device); 05184 05185 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry) 05186 { 05187 TRACE("Checking resource %p for eviction.\n", resource); 05188 05189 if (resource->pool == WINED3D_POOL_MANAGED) 05190 { 05191 TRACE("Evicting %p.\n", resource); 05192 resource->resource_ops->resource_unload(resource); 05193 } 05194 } 05195 05196 /* Invalidate stream sources, the buffer(s) may have been evicted. */ 05197 device_invalidate_state(device, STATE_STREAMSRC); 05198 } 05199 05200 static BOOL is_display_mode_supported(const struct wined3d_device *device, 05201 const struct wined3d_swapchain_desc *swapchain_desc) 05202 { 05203 struct wined3d_display_mode m; 05204 UINT i, count; 05205 HRESULT hr; 05206 05207 /* All Windowed modes are supported, as is leaving the current mode */ 05208 if (swapchain_desc->windowed) 05209 return TRUE; 05210 if (!swapchain_desc->backbuffer_width) 05211 return TRUE; 05212 if (!swapchain_desc->backbuffer_height) 05213 return TRUE; 05214 05215 count = wined3d_get_adapter_mode_count(device->wined3d, device->adapter->ordinal, WINED3DFMT_UNKNOWN); 05216 for (i = 0; i < count; ++i) 05217 { 05218 memset(&m, 0, sizeof(m)); 05219 hr = wined3d_enum_adapter_modes(device->wined3d, device->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m); 05220 if (FAILED(hr)) 05221 ERR("Failed to enumerate adapter mode.\n"); 05222 if (m.width == swapchain_desc->backbuffer_width && m.height == swapchain_desc->backbuffer_height) 05223 /* Mode found, it is supported. */ 05224 return TRUE; 05225 } 05226 /* Mode not found -> not supported */ 05227 return FALSE; 05228 } 05229 05230 /* Do not call while under the GL lock. */ 05231 static void delete_opengl_contexts(struct wined3d_device *device, struct wined3d_swapchain *swapchain) 05232 { 05233 struct wined3d_resource *resource, *cursor; 05234 const struct wined3d_gl_info *gl_info; 05235 struct wined3d_context *context; 05236 struct wined3d_shader *shader; 05237 05238 context = context_acquire(device, NULL); 05239 gl_info = context->gl_info; 05240 05241 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry) 05242 { 05243 TRACE("Unloading resource %p.\n", resource); 05244 05245 resource->resource_ops->resource_unload(resource); 05246 } 05247 05248 LIST_FOR_EACH_ENTRY(shader, &device->shaders, struct wined3d_shader, shader_list_entry) 05249 { 05250 device->shader_backend->shader_destroy(shader); 05251 } 05252 05253 ENTER_GL(); 05254 if (device->depth_blt_texture) 05255 { 05256 glDeleteTextures(1, &device->depth_blt_texture); 05257 device->depth_blt_texture = 0; 05258 } 05259 if (device->cursorTexture) 05260 { 05261 glDeleteTextures(1, &device->cursorTexture); 05262 device->cursorTexture = 0; 05263 } 05264 LEAVE_GL(); 05265 05266 device->blitter->free_private(device); 05267 device->frag_pipe->free_private(device); 05268 device->shader_backend->shader_free_private(device); 05269 destroy_dummy_textures(device, gl_info); 05270 05271 context_release(context); 05272 05273 while (device->context_count) 05274 { 05275 swapchain_destroy_contexts(device->contexts[0]->swapchain); 05276 } 05277 05278 HeapFree(GetProcessHeap(), 0, swapchain->context); 05279 swapchain->context = NULL; 05280 } 05281 05282 /* Do not call while under the GL lock. */ 05283 static HRESULT create_primary_opengl_context(struct wined3d_device *device, struct wined3d_swapchain *swapchain) 05284 { 05285 struct wined3d_context *context; 05286 struct wined3d_surface *target; 05287 HRESULT hr; 05288 05289 /* Recreate the primary swapchain's context */ 05290 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context)); 05291 if (!swapchain->context) 05292 { 05293 ERR("Failed to allocate memory for swapchain context array.\n"); 05294 return E_OUTOFMEMORY; 05295 } 05296 05297 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer; 05298 if (!(context = context_create(swapchain, target, swapchain->ds_format))) 05299 { 05300 WARN("Failed to create context.\n"); 05301 HeapFree(GetProcessHeap(), 0, swapchain->context); 05302 return E_FAIL; 05303 } 05304 05305 swapchain->context[0] = context; 05306 swapchain->num_contexts = 1; 05307 create_dummy_textures(device, context); 05308 context_release(context); 05309 05310 hr = device->shader_backend->shader_alloc_private(device); 05311 if (FAILED(hr)) 05312 { 05313 ERR("Failed to allocate shader private data, hr %#x.\n", hr); 05314 goto err; 05315 } 05316 05317 hr = device->frag_pipe->alloc_private(device); 05318 if (FAILED(hr)) 05319 { 05320 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr); 05321 device->shader_backend->shader_free_private(device); 05322 goto err; 05323 } 05324 05325 hr = device->blitter->alloc_private(device); 05326 if (FAILED(hr)) 05327 { 05328 ERR("Failed to allocate blitter private data, hr %#x.\n", hr); 05329 device->frag_pipe->free_private(device); 05330 device->shader_backend->shader_free_private(device); 05331 goto err; 05332 } 05333 05334 return WINED3D_OK; 05335 05336 err: 05337 context_acquire(device, NULL); 05338 destroy_dummy_textures(device, context->gl_info); 05339 context_release(context); 05340 context_destroy(device, context); 05341 HeapFree(GetProcessHeap(), 0, swapchain->context); 05342 swapchain->num_contexts = 0; 05343 return hr; 05344 } 05345 05346 /* Do not call while under the GL lock. */ 05347 HRESULT CDECL wined3d_device_reset(struct wined3d_device *device, 05348 const struct wined3d_swapchain_desc *swapchain_desc, 05349 wined3d_device_reset_cb callback) 05350 { 05351 struct wined3d_resource *resource, *cursor; 05352 struct wined3d_swapchain *swapchain; 05353 struct wined3d_display_mode mode; 05354 BOOL DisplayModeChanged = FALSE; 05355 BOOL update_desc = FALSE; 05356 HRESULT hr; 05357 05358 TRACE("device %p, swapchain_desc %p.\n", device, swapchain_desc); 05359 05360 stateblock_unbind_resources(device->stateBlock); 05361 05362 if (device->onscreen_depth_stencil) 05363 { 05364 wined3d_surface_decref(device->onscreen_depth_stencil); 05365 device->onscreen_depth_stencil = NULL; 05366 } 05367 05368 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry) 05369 { 05370 TRACE("Enumerating resource %p.\n", resource); 05371 if (FAILED(hr = callback(resource))) 05372 return hr; 05373 } 05374 05375 hr = wined3d_device_get_swapchain(device, 0, &swapchain); 05376 if (FAILED(hr)) 05377 { 05378 ERR("Failed to get the first implicit swapchain\n"); 05379 return hr; 05380 } 05381 05382 if (!is_display_mode_supported(device, swapchain_desc)) 05383 { 05384 WARN("Rejecting reset() call because the requested display mode is not supported.\n"); 05385 WARN("Requested mode: %ux%u.\n", 05386 swapchain_desc->backbuffer_width, 05387 swapchain_desc->backbuffer_height); 05388 wined3d_swapchain_decref(swapchain); 05389 return WINED3DERR_INVALIDCALL; 05390 } 05391 05392 /* Is it necessary to recreate the gl context? Actually every setting can be changed 05393 * on an existing gl context, so there's no real need for recreation. 05394 * 05395 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED 05396 * 05397 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain 05398 */ 05399 TRACE("New params:\n"); 05400 TRACE("backbuffer_width %u\n", swapchain_desc->backbuffer_width); 05401 TRACE("backbuffer_height %u\n", swapchain_desc->backbuffer_height); 05402 TRACE("backbuffer_format %s\n", debug_d3dformat(swapchain_desc->backbuffer_format)); 05403 TRACE("backbuffer_count %u\n", swapchain_desc->backbuffer_count); 05404 TRACE("multisample_type %#x\n", swapchain_desc->multisample_type); 05405 TRACE("multisample_quality %u\n", swapchain_desc->multisample_quality); 05406 TRACE("swap_effect %#x\n", swapchain_desc->swap_effect); 05407 TRACE("device_window %p\n", swapchain_desc->device_window); 05408 TRACE("windowed %#x\n", swapchain_desc->windowed); 05409 TRACE("enable_auto_depth_stencil %#x\n", swapchain_desc->enable_auto_depth_stencil); 05410 if (swapchain_desc->enable_auto_depth_stencil) 05411 TRACE("auto_depth_stencil_format %s\n", debug_d3dformat(swapchain_desc->auto_depth_stencil_format)); 05412 TRACE("flags %#x\n", swapchain_desc->flags); 05413 TRACE("refresh_rate %u\n", swapchain_desc->refresh_rate); 05414 TRACE("swap_interval %u\n", swapchain_desc->swap_interval); 05415 TRACE("auto_restore_display_mode %#x\n", swapchain_desc->auto_restore_display_mode); 05416 05417 /* No special treatment of these parameters. Just store them */ 05418 swapchain->desc.swap_effect = swapchain_desc->swap_effect; 05419 swapchain->desc.flags = swapchain_desc->flags; 05420 swapchain->desc.swap_interval = swapchain_desc->swap_interval; 05421 swapchain->desc.refresh_rate = swapchain_desc->refresh_rate; 05422 05423 /* What to do about these? */ 05424 if (swapchain_desc->backbuffer_count 05425 && swapchain_desc->backbuffer_count != swapchain->desc.backbuffer_count) 05426 FIXME("Cannot change the back buffer count yet.\n"); 05427 05428 if (swapchain_desc->device_window 05429 && swapchain_desc->device_window != swapchain->desc.device_window) 05430 FIXME("Cannot change the device window yet.\n"); 05431 05432 if (swapchain_desc->enable_auto_depth_stencil && !device->auto_depth_stencil) 05433 { 05434 HRESULT hrc; 05435 05436 TRACE("Creating the depth stencil buffer\n"); 05437 05438 hrc = device->device_parent->ops->create_depth_stencil(device->device_parent, 05439 swapchain_desc->backbuffer_width, 05440 swapchain_desc->backbuffer_height, 05441 swapchain_desc->auto_depth_stencil_format, 05442 swapchain_desc->multisample_type, 05443 swapchain_desc->multisample_quality, 05444 FALSE, 05445 &device->auto_depth_stencil); 05446 if (FAILED(hrc)) 05447 { 05448 ERR("Failed to create the depth stencil buffer.\n"); 05449 wined3d_swapchain_decref(swapchain); 05450 return WINED3DERR_INVALIDCALL; 05451 } 05452 } 05453 05454 if (device->onscreen_depth_stencil) 05455 { 05456 wined3d_surface_decref(device->onscreen_depth_stencil); 05457 device->onscreen_depth_stencil = NULL; 05458 } 05459 05460 /* Reset the depth stencil */ 05461 if (swapchain_desc->enable_auto_depth_stencil) 05462 wined3d_device_set_depth_stencil(device, device->auto_depth_stencil); 05463 else 05464 wined3d_device_set_depth_stencil(device, NULL); 05465 05466 TRACE("Resetting stateblock\n"); 05467 wined3d_stateblock_decref(device->updateStateBlock); 05468 wined3d_stateblock_decref(device->stateBlock); 05469 05470 if (swapchain_desc->windowed) 05471 { 05472 mode.width = swapchain->orig_width; 05473 mode.height = swapchain->orig_height; 05474 mode.refresh_rate = 0; 05475 mode.format_id = swapchain->desc.backbuffer_format; 05476 } 05477 else 05478 { 05479 mode.width = swapchain_desc->backbuffer_width; 05480 mode.height = swapchain_desc->backbuffer_height; 05481 mode.refresh_rate = swapchain_desc->refresh_rate; 05482 mode.format_id = swapchain_desc->backbuffer_format; 05483 } 05484 05485 /* Should Width == 800 && Height == 0 set 800x600? */ 05486 if (swapchain_desc->backbuffer_width && swapchain_desc->backbuffer_height 05487 && (swapchain_desc->backbuffer_width != swapchain->desc.backbuffer_width 05488 || swapchain_desc->backbuffer_height != swapchain->desc.backbuffer_height)) 05489 { 05490 if (!swapchain_desc->windowed) 05491 DisplayModeChanged = TRUE; 05492 05493 swapchain->desc.backbuffer_width = swapchain_desc->backbuffer_width; 05494 swapchain->desc.backbuffer_height = swapchain_desc->backbuffer_height; 05495 update_desc = TRUE; 05496 } 05497 05498 if (swapchain_desc->backbuffer_format != WINED3DFMT_UNKNOWN 05499 && swapchain_desc->backbuffer_format != swapchain->desc.backbuffer_format) 05500 { 05501 swapchain->desc.backbuffer_format = swapchain_desc->backbuffer_format; 05502 update_desc = TRUE; 05503 } 05504 05505 if (swapchain_desc->multisample_type != swapchain->desc.multisample_type 05506 || swapchain_desc->multisample_quality != swapchain->desc.multisample_quality) 05507 { 05508 swapchain->desc.multisample_type = swapchain_desc->multisample_type; 05509 swapchain->desc.multisample_quality = swapchain_desc->multisample_quality; 05510 update_desc = TRUE; 05511 } 05512 05513 if (update_desc) 05514 { 05515 UINT i; 05516 05517 hr = wined3d_surface_update_desc(swapchain->front_buffer, swapchain->desc.backbuffer_width, 05518 swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format, 05519 swapchain->desc.multisample_type, swapchain->desc.multisample_quality); 05520 if (FAILED(hr)) 05521 { 05522 wined3d_swapchain_decref(swapchain); 05523 return hr; 05524 } 05525 05526 for (i = 0; i < swapchain->desc.backbuffer_count; ++i) 05527 { 05528 hr = wined3d_surface_update_desc(swapchain->back_buffers[i], swapchain->desc.backbuffer_width, 05529 swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format, 05530 swapchain->desc.multisample_type, swapchain->desc.multisample_quality); 05531 if (FAILED(hr)) 05532 { 05533 wined3d_swapchain_decref(swapchain); 05534 return hr; 05535 } 05536 } 05537 if (device->auto_depth_stencil) 05538 { 05539 hr = wined3d_surface_update_desc(device->auto_depth_stencil, swapchain->desc.backbuffer_width, 05540 swapchain->desc.backbuffer_height, device->auto_depth_stencil->resource.format->id, 05541 swapchain->desc.multisample_type, swapchain->desc.multisample_quality); 05542 if (FAILED(hr)) 05543 { 05544 wined3d_swapchain_decref(swapchain); 05545 return hr; 05546 } 05547 } 05548 } 05549 05550 if (device->d3d_initialized) 05551 delete_opengl_contexts(device, swapchain); 05552 05553 if (!swapchain_desc->windowed != !swapchain->desc.windowed 05554 || DisplayModeChanged) 05555 { 05556 wined3d_device_set_display_mode(device, 0, &mode); 05557 05558 if (!swapchain_desc->windowed) 05559 { 05560 if (swapchain->desc.windowed) 05561 { 05562 HWND focus_window = device->create_parms.focus_window; 05563 if (!focus_window) 05564 focus_window = swapchain_desc->device_window; 05565 if (FAILED(hr = wined3d_device_acquire_focus_window(device, focus_window))) 05566 { 05567 ERR("Failed to acquire focus window, hr %#x.\n", hr); 05568 wined3d_swapchain_decref(swapchain); 05569 return hr; 05570 } 05571 05572 /* switch from windowed to fs */ 05573 wined3d_device_setup_fullscreen_window(device, swapchain->device_window, 05574 swapchain_desc->backbuffer_width, 05575 swapchain_desc->backbuffer_height); 05576 } 05577 else 05578 { 05579 /* Fullscreen -> fullscreen mode change */ 05580 MoveWindow(swapchain->device_window, 0, 0, 05581 swapchain_desc->backbuffer_width, 05582 swapchain_desc->backbuffer_height, 05583 TRUE); 05584 } 05585 } 05586 else if (!swapchain->desc.windowed) 05587 { 05588 /* Fullscreen -> windowed switch */ 05589 wined3d_device_restore_fullscreen_window(device, swapchain->device_window); 05590 wined3d_device_release_focus_window(device); 05591 } 05592 swapchain->desc.windowed = swapchain_desc->windowed; 05593 } 05594 else if (!swapchain_desc->windowed) 05595 { 05596 DWORD style = device->style; 05597 DWORD exStyle = device->exStyle; 05598 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into 05599 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call 05600 * Reset to clear up their mess. Guild Wars also loses the device during that. 05601 */ 05602 device->style = 0; 05603 device->exStyle = 0; 05604 wined3d_device_setup_fullscreen_window(device, swapchain->device_window, 05605 swapchain_desc->backbuffer_width, 05606 swapchain_desc->backbuffer_height); 05607 device->style = style; 05608 device->exStyle = exStyle; 05609 } 05610 05611 /* Note: No parent needed for initial internal stateblock */ 05612 hr = wined3d_stateblock_create(device, WINED3D_SBT_INIT, &device->stateBlock); 05613 if (FAILED(hr)) 05614 ERR("Resetting the stateblock failed with error %#x.\n", hr); 05615 else 05616 TRACE("Created stateblock %p.\n", device->stateBlock); 05617 device->updateStateBlock = device->stateBlock; 05618 wined3d_stateblock_incref(device->updateStateBlock); 05619 05620 stateblock_init_default_state(device->stateBlock); 05621 05622 swapchain_update_render_to_fbo(swapchain); 05623 swapchain_update_draw_bindings(swapchain); 05624 05625 if (device->d3d_initialized) 05626 hr = create_primary_opengl_context(device, swapchain); 05627 wined3d_swapchain_decref(swapchain); 05628 05629 /* All done. There is no need to reload resources or shaders, this will happen automatically on the 05630 * first use 05631 */ 05632 return hr; 05633 } 05634 05635 HRESULT CDECL wined3d_device_set_dialog_box_mode(struct wined3d_device *device, BOOL enable_dialogs) 05636 { 05637 TRACE("device %p, enable_dialogs %#x.\n", device, enable_dialogs); 05638 05639 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n"); 05640 05641 return WINED3D_OK; 05642 } 05643 05644 05645 HRESULT CDECL wined3d_device_get_creation_parameters(const struct wined3d_device *device, 05646 struct wined3d_device_creation_parameters *parameters) 05647 { 05648 TRACE("device %p, parameters %p.\n", device, parameters); 05649 05650 *parameters = device->create_parms; 05651 return WINED3D_OK; 05652 } 05653 05654 void CDECL wined3d_device_set_gamma_ramp(const struct wined3d_device *device, 05655 UINT swapchain_idx, DWORD flags, const struct wined3d_gamma_ramp *ramp) 05656 { 05657 struct wined3d_swapchain *swapchain; 05658 05659 TRACE("device %p, swapchain_idx %u, flags %#x, ramp %p.\n", 05660 device, swapchain_idx, flags, ramp); 05661 05662 if (SUCCEEDED(wined3d_device_get_swapchain(device, swapchain_idx, &swapchain))) 05663 { 05664 wined3d_swapchain_set_gamma_ramp(swapchain, flags, ramp); 05665 wined3d_swapchain_decref(swapchain); 05666 } 05667 } 05668 05669 void CDECL wined3d_device_get_gamma_ramp(const struct wined3d_device *device, 05670 UINT swapchain_idx, struct wined3d_gamma_ramp *ramp) 05671 { 05672 struct wined3d_swapchain *swapchain; 05673 05674 TRACE("device %p, swapchain_idx %u, ramp %p.\n", 05675 device, swapchain_idx, ramp); 05676 05677 if (SUCCEEDED(wined3d_device_get_swapchain(device, swapchain_idx, &swapchain))) 05678 { 05679 wined3d_swapchain_get_gamma_ramp(swapchain, ramp); 05680 wined3d_swapchain_decref(swapchain); 05681 } 05682 } 05683 05684 void device_resource_add(struct wined3d_device *device, struct wined3d_resource *resource) 05685 { 05686 TRACE("device %p, resource %p.\n", device, resource); 05687 05688 list_add_head(&device->resources, &resource->resource_list_entry); 05689 } 05690 05691 static void device_resource_remove(struct wined3d_device *device, struct wined3d_resource *resource) 05692 { 05693 TRACE("device %p, resource %p.\n", device, resource); 05694 05695 list_remove(&resource->resource_list_entry); 05696 } 05697 05698 void device_resource_released(struct wined3d_device *device, struct wined3d_resource *resource) 05699 { 05700 enum wined3d_resource_type type = resource->type; 05701 unsigned int i; 05702 05703 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type)); 05704 05705 context_resource_released(device, resource, type); 05706 05707 switch (type) 05708 { 05709 case WINED3D_RTYPE_SURFACE: 05710 { 05711 struct wined3d_surface *surface = surface_from_resource(resource); 05712 05713 if (!device->d3d_initialized) break; 05714 05715 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i) 05716 { 05717 if (device->fb.render_targets[i] == surface) 05718 { 05719 ERR("Surface %p is still in use as render target %u.\n", surface, i); 05720 device->fb.render_targets[i] = NULL; 05721 } 05722 } 05723 05724 if (device->fb.depth_stencil == surface) 05725 { 05726 ERR("Surface %p is still in use as depth/stencil buffer.\n", surface); 05727 device->fb.depth_stencil = NULL; 05728 } 05729 } 05730 break; 05731 05732 case WINED3D_RTYPE_TEXTURE: 05733 case WINED3D_RTYPE_CUBE_TEXTURE: 05734 case WINED3D_RTYPE_VOLUME_TEXTURE: 05735 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i) 05736 { 05737 struct wined3d_texture *texture = wined3d_texture_from_resource(resource); 05738 05739 if (device->stateBlock && device->stateBlock->state.textures[i] == texture) 05740 { 05741 ERR("Texture %p is still in use by stateblock %p, stage %u.\n", 05742 texture, device->stateBlock, i); 05743 device->stateBlock->state.textures[i] = NULL; 05744 } 05745 05746 if (device->updateStateBlock != device->stateBlock 05747 && device->updateStateBlock->state.textures[i] == texture) 05748 { 05749 ERR("Texture %p is still in use by stateblock %p, stage %u.\n", 05750 texture, device->updateStateBlock, i); 05751 device->updateStateBlock->state.textures[i] = NULL; 05752 } 05753 } 05754 break; 05755 05756 case WINED3D_RTYPE_BUFFER: 05757 { 05758 struct wined3d_buffer *buffer = buffer_from_resource(resource); 05759 05760 for (i = 0; i < MAX_STREAMS; ++i) 05761 { 05762 if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer) 05763 { 05764 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n", 05765 buffer, device->stateBlock, i); 05766 device->stateBlock->state.streams[i].buffer = NULL; 05767 } 05768 05769 if (device->updateStateBlock != device->stateBlock 05770 && device->updateStateBlock->state.streams[i].buffer == buffer) 05771 { 05772 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n", 05773 buffer, device->updateStateBlock, i); 05774 device->updateStateBlock->state.streams[i].buffer = NULL; 05775 } 05776 05777 } 05778 05779 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer) 05780 { 05781 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n", 05782 buffer, device->stateBlock); 05783 device->stateBlock->state.index_buffer = NULL; 05784 } 05785 05786 if (device->updateStateBlock != device->stateBlock 05787 && device->updateStateBlock->state.index_buffer == buffer) 05788 { 05789 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n", 05790 buffer, device->updateStateBlock); 05791 device->updateStateBlock->state.index_buffer = NULL; 05792 } 05793 } 05794 break; 05795 05796 default: 05797 break; 05798 } 05799 05800 /* Remove the resource from the resourceStore */ 05801 device_resource_remove(device, resource); 05802 05803 TRACE("Resource released.\n"); 05804 } 05805 05806 HRESULT CDECL wined3d_device_get_surface_from_dc(const struct wined3d_device *device, 05807 HDC dc, struct wined3d_surface **surface) 05808 { 05809 struct wined3d_resource *resource; 05810 05811 TRACE("device %p, dc %p, surface %p.\n", device, dc, surface); 05812 05813 if (!dc) 05814 return WINED3DERR_INVALIDCALL; 05815 05816 LIST_FOR_EACH_ENTRY(resource, &device->resources, struct wined3d_resource, resource_list_entry) 05817 { 05818 if (resource->type == WINED3D_RTYPE_SURFACE) 05819 { 05820 struct wined3d_surface *s = surface_from_resource(resource); 05821 05822 if (s->hDC == dc) 05823 { 05824 TRACE("Found surface %p for dc %p.\n", s, dc); 05825 *surface = s; 05826 return WINED3D_OK; 05827 } 05828 } 05829 } 05830 05831 return WINED3DERR_INVALIDCALL; 05832 } 05833 05834 HRESULT device_init(struct wined3d_device *device, struct wined3d *wined3d, 05835 UINT adapter_idx, enum wined3d_device_type device_type, HWND focus_window, DWORD flags, 05836 BYTE surface_alignment, struct wined3d_device_parent *device_parent) 05837 { 05838 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx]; 05839 const struct fragment_pipeline *fragment_pipeline; 05840 struct wined3d_display_mode mode; 05841 struct shader_caps shader_caps; 05842 struct fragment_caps ffp_caps; 05843 unsigned int i; 05844 HRESULT hr; 05845 05846 device->ref = 1; 05847 device->wined3d = wined3d; 05848 wined3d_incref(device->wined3d); 05849 device->adapter = wined3d->adapter_count ? adapter : NULL; 05850 device->device_parent = device_parent; 05851 list_init(&device->resources); 05852 list_init(&device->shaders); 05853 device->surface_alignment = surface_alignment; 05854 05855 /* Get the initial screen setup for ddraw. */ 05856 hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &mode); 05857 if (FAILED(hr)) 05858 { 05859 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr); 05860 wined3d_decref(device->wined3d); 05861 return hr; 05862 } 05863 adapter->screen_size.cx = mode.width; 05864 adapter->screen_size.cy = mode.height; 05865 adapter->screen_format = mode.format_id; 05866 05867 /* Save the creation parameters. */ 05868 device->create_parms.adapter_idx = adapter_idx; 05869 device->create_parms.device_type = device_type; 05870 device->create_parms.focus_window = focus_window; 05871 device->create_parms.flags = flags; 05872 05873 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]); 05874 05875 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode); 05876 device->shader_backend = adapter->shader_backend; 05877 05878 if (device->shader_backend) 05879 { 05880 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps); 05881 device->vshader_version = shader_caps.VertexShaderVersion; 05882 device->pshader_version = shader_caps.PixelShaderVersion; 05883 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst; 05884 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst; 05885 device->vs_clipping = shader_caps.VSClipping; 05886 } 05887 fragment_pipeline = adapter->fragment_pipe; 05888 device->frag_pipe = fragment_pipeline; 05889 if (fragment_pipeline) 05890 { 05891 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps); 05892 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures; 05893 05894 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info, 05895 ffp_vertexstate_template, fragment_pipeline, misc_state_template); 05896 if (FAILED(hr)) 05897 { 05898 ERR("Failed to compile state table, hr %#x.\n", hr); 05899 wined3d_decref(device->wined3d); 05900 return hr; 05901 } 05902 } 05903 device->blitter = adapter->blitter; 05904 05905 hr = wined3d_stateblock_create(device, WINED3D_SBT_INIT, &device->stateBlock); 05906 if (FAILED(hr)) 05907 { 05908 WARN("Failed to create stateblock.\n"); 05909 for (i = 0; i < sizeof(device->multistate_funcs) / sizeof(device->multistate_funcs[0]); ++i) 05910 { 05911 HeapFree(GetProcessHeap(), 0, device->multistate_funcs[i]); 05912 } 05913 wined3d_decref(device->wined3d); 05914 return hr; 05915 } 05916 05917 TRACE("Created stateblock %p.\n", device->stateBlock); 05918 device->updateStateBlock = device->stateBlock; 05919 wined3d_stateblock_incref(device->updateStateBlock); 05920 05921 return WINED3D_OK; 05922 } 05923 05924 05925 void device_invalidate_state(const struct wined3d_device *device, DWORD state) 05926 { 05927 DWORD rep = device->StateTable[state].representative; 05928 struct wined3d_context *context; 05929 DWORD idx; 05930 BYTE shift; 05931 UINT i; 05932 05933 for (i = 0; i < device->context_count; ++i) 05934 { 05935 context = device->contexts[i]; 05936 if(isStateDirty(context, rep)) continue; 05937 05938 context->dirtyArray[context->numDirtyEntries++] = rep; 05939 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT); 05940 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1); 05941 context->isStateDirty[idx] |= (1 << shift); 05942 } 05943 } 05944 05945 void get_drawable_size_fbo(const struct wined3d_context *context, UINT *width, UINT *height) 05946 { 05947 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */ 05948 *width = context->current_rt->pow2Width; 05949 *height = context->current_rt->pow2Height; 05950 } 05951 05952 void get_drawable_size_backbuffer(const struct wined3d_context *context, UINT *width, UINT *height) 05953 { 05954 const struct wined3d_swapchain *swapchain = context->swapchain; 05955 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the 05956 * current context's drawable, which is the size of the back buffer of the swapchain 05957 * the active context belongs to. */ 05958 *width = swapchain->desc.backbuffer_width; 05959 *height = swapchain->desc.backbuffer_height; 05960 } 05961 05962 LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL unicode, 05963 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc) 05964 { 05965 wined3d_mutex_lock(); 05966 05967 if (device->filter_messages) 05968 { 05969 wined3d_mutex_unlock(); 05970 05971 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n", 05972 window, message, wparam, lparam); 05973 if (unicode) 05974 return DefWindowProcW(window, message, wparam, lparam); 05975 else 05976 return DefWindowProcA(window, message, wparam, lparam); 05977 } 05978 05979 if (message == WM_DESTROY) 05980 { 05981 TRACE("unregister window %p.\n", window); 05982 wined3d_unregister_window(window); 05983 05984 if (device->focus_window == window) device->focus_window = NULL; 05985 else ERR("Window %p is not the focus window for device %p.\n", window, device); 05986 } 05987 else if (message == WM_DISPLAYCHANGE) 05988 { 05989 device->device_parent->ops->mode_changed(device->device_parent); 05990 } 05991 05992 wined3d_mutex_unlock(); 05993 05994 if (unicode) 05995 return CallWindowProcW(proc, window, message, wparam, lparam); 05996 else 05997 return CallWindowProcA(proc, window, message, wparam, lparam); 05998 } Generated on Sun May 27 2012 04:21:21 for ReactOS by
1.7.6.1
|