ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

device.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(&current_rect, 0, 0,
00609                 ds->ds_current_size.cx,
00610                 ds->ds_current_size.cy);
00611     else
00612         SetRectEmpty(&current_rect);
00613 
00614     IntersectRect(&r, draw_rect, &current_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, &current_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(&current_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(&current_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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.