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

buffer.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2002-2005 Jason Edmeades
00003  * Copyright 2002-2005 Raphael Junqueira
00004  * Copyright 2004 Christian Costa
00005  * Copyright 2005 Oliver Stieber
00006  * Copyright 2007-2010 Stefan Dösinger for CodeWeavers
00007  * Copyright 2009-2010 Henri Verbeet for CodeWeavers
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00022  *
00023  */
00024 
00025 #include "config.h"
00026 #include "wine/port.h"
00027 
00028 #include "wined3d_private.h"
00029 
00030 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
00031 
00032 #define VB_MAXDECLCHANGES     100     /* After that number of decl changes we stop converting */
00033 #define VB_RESETDECLCHANGE    1000    /* Reset the decl changecount after that number of draws */
00034 #define VB_MAXFULLCONVERSIONS 5       /* Number of full conversions before we stop converting */
00035 #define VB_RESETFULLCONVS     20      /* Reset full conversion counts after that number of draws */
00036 
00037 static inline BOOL buffer_add_dirty_area(struct wined3d_buffer *This, UINT offset, UINT size)
00038 {
00039     if (!This->buffer_object) return TRUE;
00040 
00041     if (This->maps_size <= This->modified_areas)
00042     {
00043         void *new = HeapReAlloc(GetProcessHeap(), 0, This->maps,
00044                                 This->maps_size * 2 * sizeof(*This->maps));
00045         if (!new)
00046         {
00047             ERR("Out of memory\n");
00048             return FALSE;
00049         }
00050         else
00051         {
00052             This->maps = new;
00053             This->maps_size *= 2;
00054         }
00055     }
00056 
00057     if(offset > This->resource.size || offset + size > This->resource.size)
00058     {
00059         WARN("Invalid range dirtified, marking entire buffer dirty\n");
00060         offset = 0;
00061         size = This->resource.size;
00062     }
00063     else if(!offset && !size)
00064     {
00065         size = This->resource.size;
00066     }
00067 
00068     This->maps[This->modified_areas].offset = offset;
00069     This->maps[This->modified_areas].size = size;
00070     This->modified_areas++;
00071     return TRUE;
00072 }
00073 
00074 static inline void buffer_clear_dirty_areas(struct wined3d_buffer *This)
00075 {
00076     This->modified_areas = 0;
00077 }
00078 
00079 static BOOL buffer_is_dirty(const struct wined3d_buffer *buffer)
00080 {
00081     return !!buffer->modified_areas;
00082 }
00083 
00084 static BOOL buffer_is_fully_dirty(const struct wined3d_buffer *buffer)
00085 {
00086     unsigned int i;
00087 
00088     for (i = 0; i < buffer->modified_areas; ++i)
00089     {
00090         if (!buffer->maps[i].offset && buffer->maps[i].size == buffer->resource.size)
00091             return TRUE;
00092     }
00093     return FALSE;
00094 }
00095 
00096 /* Context activation is done by the caller */
00097 static void delete_gl_buffer(struct wined3d_buffer *This, const struct wined3d_gl_info *gl_info)
00098 {
00099     if(!This->buffer_object) return;
00100 
00101     ENTER_GL();
00102     GL_EXTCALL(glDeleteBuffersARB(1, &This->buffer_object));
00103     checkGLcall("glDeleteBuffersARB");
00104     LEAVE_GL();
00105     This->buffer_object = 0;
00106 
00107     if(This->query)
00108     {
00109         wined3d_event_query_destroy(This->query);
00110         This->query = NULL;
00111     }
00112     This->flags &= ~WINED3D_BUFFER_APPLESYNC;
00113 }
00114 
00115 /* Context activation is done by the caller. */
00116 static void buffer_create_buffer_object(struct wined3d_buffer *This, const struct wined3d_gl_info *gl_info)
00117 {
00118     GLenum error, gl_usage;
00119 
00120     TRACE("Creating an OpenGL vertex buffer object for wined3d_buffer %p with usage %s.\n",
00121             This, debug_d3dusage(This->resource.usage));
00122 
00123     ENTER_GL();
00124 
00125     /* Make sure that the gl error is cleared. Do not use checkGLcall
00126     * here because checkGLcall just prints a fixme and continues. However,
00127     * if an error during VBO creation occurs we can fall back to non-vbo operation
00128     * with full functionality(but performance loss)
00129     */
00130     while (glGetError() != GL_NO_ERROR);
00131 
00132     /* Basically the FVF parameter passed to CreateVertexBuffer is no good.
00133      * The vertex declaration from the device determines how the data in the
00134      * buffer is interpreted. This means that on each draw call the buffer has
00135      * to be verified to check if the rhw and color values are in the correct
00136      * format. */
00137 
00138     GL_EXTCALL(glGenBuffersARB(1, &This->buffer_object));
00139     error = glGetError();
00140     if (!This->buffer_object || error != GL_NO_ERROR)
00141     {
00142         ERR("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
00143         LEAVE_GL();
00144         goto fail;
00145     }
00146 
00147     if (This->buffer_type_hint == GL_ELEMENT_ARRAY_BUFFER_ARB)
00148         device_invalidate_state(This->resource.device, STATE_INDEXBUFFER);
00149     GL_EXTCALL(glBindBufferARB(This->buffer_type_hint, This->buffer_object));
00150     error = glGetError();
00151     if (error != GL_NO_ERROR)
00152     {
00153         ERR("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
00154         LEAVE_GL();
00155         goto fail;
00156     }
00157 
00158     /* Don't use static, because dx apps tend to update the buffer
00159      * quite often even if they specify 0 usage.
00160      */
00161     if(This->resource.usage & WINED3DUSAGE_DYNAMIC)
00162     {
00163         TRACE("Gl usage = GL_STREAM_DRAW_ARB\n");
00164         gl_usage = GL_STREAM_DRAW_ARB;
00165 
00166         if(gl_info->supported[APPLE_FLUSH_BUFFER_RANGE])
00167         {
00168             GL_EXTCALL(glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE));
00169             checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE)");
00170             This->flags |= WINED3D_BUFFER_FLUSH;
00171 
00172             GL_EXTCALL(glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE));
00173             checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE)");
00174             This->flags |= WINED3D_BUFFER_APPLESYNC;
00175         }
00176         /* No setup is needed here for GL_ARB_map_buffer_range */
00177     }
00178     else
00179     {
00180         TRACE("Gl usage = GL_DYNAMIC_DRAW_ARB\n");
00181         gl_usage = GL_DYNAMIC_DRAW_ARB;
00182     }
00183 
00184     /* Reserve memory for the buffer. The amount of data won't change
00185      * so we are safe with calling glBufferData once and
00186      * calling glBufferSubData on updates. Upload the actual data in case
00187      * we're not double buffering, so we can release the heap mem afterwards
00188      */
00189     GL_EXTCALL(glBufferDataARB(This->buffer_type_hint, This->resource.size, This->resource.allocatedMemory, gl_usage));
00190     error = glGetError();
00191     LEAVE_GL();
00192     if (error != GL_NO_ERROR)
00193     {
00194         ERR("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
00195         goto fail;
00196     }
00197 
00198     This->buffer_object_size = This->resource.size;
00199     This->buffer_object_usage = gl_usage;
00200 
00201     if(This->flags & WINED3D_BUFFER_DOUBLEBUFFER)
00202     {
00203         if(!buffer_add_dirty_area(This, 0, 0))
00204         {
00205             ERR("buffer_add_dirty_area failed, this is not expected\n");
00206             goto fail;
00207         }
00208     }
00209     else
00210     {
00211         HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
00212         This->resource.allocatedMemory = NULL;
00213         This->resource.heapMemory = NULL;
00214     }
00215 
00216     return;
00217 
00218 fail:
00219     /* Clean up all vbo init, but continue because we can work without a vbo :-) */
00220     ERR("Failed to create a vertex buffer object. Continuing, but performance issues may occur\n");
00221     delete_gl_buffer(This, gl_info);
00222     buffer_clear_dirty_areas(This);
00223 }
00224 
00225 static BOOL buffer_process_converted_attribute(struct wined3d_buffer *This,
00226         const enum wined3d_buffer_conversion_type conversion_type,
00227         const struct wined3d_stream_info_element *attrib, DWORD *stride_this_run)
00228 {
00229     DWORD attrib_size;
00230     BOOL ret = FALSE;
00231     unsigned int i;
00232     DWORD_PTR data;
00233 
00234     /* Check for some valid situations which cause us pain. One is if the buffer is used for
00235      * constant attributes(stride = 0), the other one is if the buffer is used on two streams
00236      * with different strides. In the 2nd case we might have to drop conversion entirely,
00237      * it is possible that the same bytes are once read as FLOAT2 and once as UBYTE4N.
00238      */
00239     if (!attrib->stride)
00240     {
00241         FIXME("%s used with stride 0, let's hope we get the vertex stride from somewhere else\n",
00242                 debug_d3dformat(attrib->format->id));
00243     }
00244     else if(attrib->stride != *stride_this_run && *stride_this_run)
00245     {
00246         FIXME("Got two concurrent strides, %d and %d\n", attrib->stride, *stride_this_run);
00247     }
00248     else
00249     {
00250         *stride_this_run = attrib->stride;
00251         if (This->stride != *stride_this_run)
00252         {
00253             /* We rely that this happens only on the first converted attribute that is found,
00254              * if at all. See above check
00255              */
00256             TRACE("Reconverting because converted attributes occur, and the stride changed\n");
00257             This->stride = *stride_this_run;
00258             HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, This->conversion_map);
00259             This->conversion_map = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
00260                     sizeof(*This->conversion_map) * This->stride);
00261             ret = TRUE;
00262         }
00263     }
00264 
00265     data = ((DWORD_PTR)attrib->data.addr) % This->stride;
00266     attrib_size = attrib->format->component_count * attrib->format->component_size;
00267     for (i = 0; i < attrib_size; ++i)
00268     {
00269         DWORD_PTR idx = (data + i) % This->stride;
00270         if (This->conversion_map[idx] != conversion_type)
00271         {
00272             TRACE("Byte %ld in vertex changed\n", idx);
00273             TRACE("It was type %d, is %d now\n", This->conversion_map[idx], conversion_type);
00274             ret = TRUE;
00275             This->conversion_map[idx] = conversion_type;
00276         }
00277     }
00278 
00279     return ret;
00280 }
00281 
00282 static BOOL buffer_check_attribute(struct wined3d_buffer *This, const struct wined3d_stream_info *si,
00283         UINT attrib_idx, const BOOL check_d3dcolor, const BOOL is_ffp_position, const BOOL is_ffp_color,
00284         DWORD *stride_this_run)
00285 {
00286     const struct wined3d_stream_info_element *attrib = &si->elements[attrib_idx];
00287     enum wined3d_format_id format;
00288     BOOL ret = FALSE;
00289 
00290     /* Ignore attributes that do not have our vbo. After that check we can be sure that the attribute is
00291      * there, on nonexistent attribs the vbo is 0.
00292      */
00293     if (!(si->use_map & (1 << attrib_idx))
00294             || attrib->data.buffer_object != This->buffer_object)
00295         return FALSE;
00296 
00297     format = attrib->format->id;
00298     /* Look for newly appeared conversion */
00299     if (check_d3dcolor && format == WINED3DFMT_B8G8R8A8_UNORM)
00300     {
00301         ret = buffer_process_converted_attribute(This, CONV_D3DCOLOR, attrib, stride_this_run);
00302 
00303         if (!is_ffp_color) FIXME("Test for non-color fixed function WINED3DFMT_B8G8R8A8_UNORM format\n");
00304     }
00305     else if (is_ffp_position && format == WINED3DFMT_R32G32B32A32_FLOAT)
00306     {
00307         ret = buffer_process_converted_attribute(This, CONV_POSITIONT, attrib, stride_this_run);
00308     }
00309     else if (This->conversion_map)
00310     {
00311         ret = buffer_process_converted_attribute(This, CONV_NONE, attrib, stride_this_run);
00312     }
00313 
00314     return ret;
00315 }
00316 
00317 static BOOL buffer_find_decl(struct wined3d_buffer *This)
00318 {
00319     struct wined3d_device *device = This->resource.device;
00320     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
00321     const struct wined3d_stream_info *si = &device->strided_streams;
00322     const struct wined3d_state *state = &device->stateBlock->state;
00323     UINT stride_this_run = 0;
00324     BOOL ret = FALSE;
00325     BOOL support_d3dcolor = gl_info->supported[ARB_VERTEX_ARRAY_BGRA];
00326 
00327     /* In d3d7 the vertex buffer declaration NEVER changes because it is stored in the d3d7 vertex buffer.
00328      * Once we have our declaration there is no need to look it up again. Index buffers also never need
00329      * conversion, so once the (empty) conversion structure is created don't bother checking again
00330      */
00331     if (This->flags & WINED3D_BUFFER_HASDESC)
00332     {
00333         if(This->resource.usage & WINED3DUSAGE_STATICDECL) return FALSE;
00334     }
00335 
00336     if (use_vs(state))
00337     {
00338         TRACE("Vertex shaders used, no VBO conversion is needed\n");
00339         if(This->conversion_map)
00340         {
00341             HeapFree(GetProcessHeap(), 0, This->conversion_map);
00342             This->conversion_map = NULL;
00343             This->stride = 0;
00344             return TRUE;
00345         }
00346 
00347         return FALSE;
00348     }
00349 
00350     TRACE("Finding vertex buffer conversion information\n");
00351     /* Certain declaration types need some fixups before we can pass them to
00352      * opengl. This means D3DCOLOR attributes with fixed function vertex
00353      * processing, FLOAT4 POSITIONT with fixed function, and FLOAT16 if
00354      * GL_ARB_half_float_vertex is not supported.
00355      *
00356      * Note for d3d8 and d3d9:
00357      * The vertex buffer FVF doesn't help with finding them, we have to use
00358      * the decoded vertex declaration and pick the things that concern the
00359      * current buffer. A problem with this is that this can change between
00360      * draws, so we have to validate the information and reprocess the buffer
00361      * if it changes, and avoid false positives for performance reasons.
00362      * WineD3D doesn't even know the vertex buffer any more, it is managed
00363      * by the client libraries and passed to SetStreamSource and ProcessVertices
00364      * as needed.
00365      *
00366      * We have to distinguish between vertex shaders and fixed function to
00367      * pick the way we access the strided vertex information.
00368      *
00369      * This code sets up a per-byte array with the size of the detected
00370      * stride of the arrays in the buffer. For each byte we have a field
00371      * that marks the conversion needed on this byte. For example, the
00372      * following declaration with fixed function vertex processing:
00373      *
00374      *      POSITIONT, FLOAT4
00375      *      NORMAL, FLOAT3
00376      *      DIFFUSE, FLOAT16_4
00377      *      SPECULAR, D3DCOLOR
00378      *
00379      * Will result in
00380      * {                 POSITIONT                    }{             NORMAL                }{    DIFFUSE          }{SPECULAR }
00381      * [P][P][P][P][P][P][P][P][P][P][P][P][P][P][P][P][0][0][0][0][0][0][0][0][0][0][0][0][F][F][F][F][F][F][F][F][C][C][C][C]
00382      *
00383      * Where in this example map P means 4 component position conversion, 0
00384      * means no conversion, F means FLOAT16_2 conversion and C means D3DCOLOR
00385      * conversion (red / blue swizzle).
00386      *
00387      * If we're doing conversion and the stride changes we have to reconvert
00388      * the whole buffer. Note that we do not mind if the semantic changes,
00389      * we only care for the conversion type. So if the NORMAL is replaced
00390      * with a TEXCOORD, nothing has to be done, or if the DIFFUSE is replaced
00391      * with a D3DCOLOR BLENDWEIGHT we can happily dismiss the change. Some
00392      * conversion types depend on the semantic as well, for example a FLOAT4
00393      * texcoord needs no conversion while a FLOAT4 positiont needs one
00394      */
00395 
00396     ret = buffer_check_attribute(This, si, WINED3D_FFP_POSITION,
00397             TRUE, TRUE,  FALSE, &stride_this_run) || ret;
00398     ret = buffer_check_attribute(This, si, WINED3D_FFP_NORMAL,
00399             TRUE, FALSE, FALSE, &stride_this_run) || ret;
00400     ret = buffer_check_attribute(This, si, WINED3D_FFP_DIFFUSE,
00401             !support_d3dcolor, FALSE, TRUE,  &stride_this_run) || ret;
00402     ret = buffer_check_attribute(This, si, WINED3D_FFP_SPECULAR,
00403             !support_d3dcolor, FALSE, TRUE,  &stride_this_run) || ret;
00404     ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD0,
00405             TRUE, FALSE, FALSE, &stride_this_run) || ret;
00406     ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD1,
00407             TRUE, FALSE, FALSE, &stride_this_run) || ret;
00408     ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD2,
00409             TRUE, FALSE, FALSE, &stride_this_run) || ret;
00410     ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD3,
00411             TRUE, FALSE, FALSE, &stride_this_run) || ret;
00412     ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD4,
00413             TRUE, FALSE, FALSE, &stride_this_run) || ret;
00414     ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD5,
00415             TRUE, FALSE, FALSE, &stride_this_run) || ret;
00416     ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD6,
00417             TRUE, FALSE, FALSE, &stride_this_run) || ret;
00418     ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD7,
00419             TRUE, FALSE, FALSE, &stride_this_run) || ret;
00420 
00421     if (!stride_this_run && This->conversion_map)
00422     {
00423         /* Sanity test */
00424         if (!ret) ERR("no converted attributes found, old conversion map exists, and no declaration change?\n");
00425         HeapFree(GetProcessHeap(), 0, This->conversion_map);
00426         This->conversion_map = NULL;
00427         This->stride = 0;
00428     }
00429 
00430     if (ret) TRACE("Conversion information changed\n");
00431 
00432     return ret;
00433 }
00434 
00435 static inline void fixup_d3dcolor(DWORD *dst_color)
00436 {
00437     DWORD src_color = *dst_color;
00438 
00439     /* Color conversion like in drawStridedSlow. watch out for little endianity
00440      * If we want that stuff to work on big endian machines too we have to consider more things
00441      *
00442      * 0xff000000: Alpha mask
00443      * 0x00ff0000: Blue mask
00444      * 0x0000ff00: Green mask
00445      * 0x000000ff: Red mask
00446      */
00447     *dst_color = 0;
00448     *dst_color |= (src_color & 0xff00ff00);         /* Alpha Green */
00449     *dst_color |= (src_color & 0x00ff0000) >> 16;   /* Red */
00450     *dst_color |= (src_color & 0x000000ff) << 16;   /* Blue */
00451 }
00452 
00453 static inline void fixup_transformed_pos(float *p)
00454 {
00455     /* rhw conversion like in position_float4(). */
00456     if (p[3] != 1.0f && p[3] != 0.0f)
00457     {
00458         float w = 1.0f / p[3];
00459         p[0] *= w;
00460         p[1] *= w;
00461         p[2] *= w;
00462         p[3] = w;
00463     }
00464 }
00465 
00466 /* Context activation is done by the caller. */
00467 void buffer_get_memory(struct wined3d_buffer *buffer, const struct wined3d_gl_info *gl_info,
00468         struct wined3d_bo_address *data)
00469 {
00470     data->buffer_object = buffer->buffer_object;
00471     if (!buffer->buffer_object)
00472     {
00473         if (buffer->flags & WINED3D_BUFFER_CREATEBO)
00474         {
00475             buffer_create_buffer_object(buffer, gl_info);
00476             buffer->flags &= ~WINED3D_BUFFER_CREATEBO;
00477             if (buffer->buffer_object)
00478             {
00479                 data->buffer_object = buffer->buffer_object;
00480                 data->addr = NULL;
00481                 return;
00482             }
00483         }
00484         data->addr = buffer->resource.allocatedMemory;
00485     }
00486     else
00487     {
00488         data->addr = NULL;
00489     }
00490 }
00491 
00492 ULONG CDECL wined3d_buffer_incref(struct wined3d_buffer *buffer)
00493 {
00494     ULONG refcount = InterlockedIncrement(&buffer->resource.ref);
00495 
00496     TRACE("%p increasing refcount to %u.\n", buffer, refcount);
00497 
00498     return refcount;
00499 }
00500 
00501 /* Context activation is done by the caller. */
00502 BYTE *buffer_get_sysmem(struct wined3d_buffer *This, const struct wined3d_gl_info *gl_info)
00503 {
00504     /* AllocatedMemory exists if the buffer is double buffered or has no buffer object at all */
00505     if(This->resource.allocatedMemory) return This->resource.allocatedMemory;
00506 
00507     This->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size + RESOURCE_ALIGNMENT);
00508     This->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
00509 
00510     if (This->buffer_type_hint == GL_ELEMENT_ARRAY_BUFFER_ARB)
00511         device_invalidate_state(This->resource.device, STATE_INDEXBUFFER);
00512 
00513     ENTER_GL();
00514     GL_EXTCALL(glBindBufferARB(This->buffer_type_hint, This->buffer_object));
00515     GL_EXTCALL(glGetBufferSubDataARB(This->buffer_type_hint, 0, This->resource.size, This->resource.allocatedMemory));
00516     LEAVE_GL();
00517     This->flags |= WINED3D_BUFFER_DOUBLEBUFFER;
00518 
00519     return This->resource.allocatedMemory;
00520 }
00521 
00522 /* Do not call while under the GL lock. */
00523 static void buffer_unload(struct wined3d_resource *resource)
00524 {
00525     struct wined3d_buffer *buffer = buffer_from_resource(resource);
00526 
00527     TRACE("buffer %p.\n", buffer);
00528 
00529     if (buffer->buffer_object)
00530     {
00531         struct wined3d_device *device = resource->device;
00532         struct wined3d_context *context;
00533 
00534         context = context_acquire(device, NULL);
00535 
00536         /* Download the buffer, but don't permanently enable double buffering */
00537         if (!(buffer->flags & WINED3D_BUFFER_DOUBLEBUFFER))
00538         {
00539             buffer_get_sysmem(buffer, context->gl_info);
00540             buffer->flags &= ~WINED3D_BUFFER_DOUBLEBUFFER;
00541         }
00542 
00543         delete_gl_buffer(buffer, context->gl_info);
00544         buffer->flags |= WINED3D_BUFFER_CREATEBO; /* Recreate the buffer object next load */
00545         buffer_clear_dirty_areas(buffer);
00546 
00547         context_release(context);
00548 
00549         HeapFree(GetProcessHeap(), 0, buffer->conversion_map);
00550         buffer->conversion_map = NULL;
00551         buffer->stride = 0;
00552         buffer->conversion_stride = 0;
00553         buffer->flags &= ~WINED3D_BUFFER_HASDESC;
00554     }
00555 
00556     resource_unload(resource);
00557 }
00558 
00559 /* Do not call while under the GL lock. */
00560 ULONG CDECL wined3d_buffer_decref(struct wined3d_buffer *buffer)
00561 {
00562     ULONG refcount = InterlockedDecrement(&buffer->resource.ref);
00563 
00564     TRACE("%p decreasing refcount to %u.\n", buffer, refcount);
00565 
00566     if (!refcount)
00567     {
00568         buffer_unload(&buffer->resource);
00569         resource_cleanup(&buffer->resource);
00570         buffer->resource.parent_ops->wined3d_object_destroyed(buffer->resource.parent);
00571         HeapFree(GetProcessHeap(), 0, buffer->maps);
00572         HeapFree(GetProcessHeap(), 0, buffer);
00573     }
00574 
00575     return refcount;
00576 }
00577 
00578 void * CDECL wined3d_buffer_get_parent(const struct wined3d_buffer *buffer)
00579 {
00580     TRACE("buffer %p.\n", buffer);
00581 
00582     return buffer->resource.parent;
00583 }
00584 
00585 DWORD CDECL wined3d_buffer_set_priority(struct wined3d_buffer *buffer, DWORD priority)
00586 {
00587     return resource_set_priority(&buffer->resource, priority);
00588 }
00589 
00590 DWORD CDECL wined3d_buffer_get_priority(const struct wined3d_buffer *buffer)
00591 {
00592     return resource_get_priority(&buffer->resource);
00593 }
00594 
00595 /* The caller provides a context and binds the buffer */
00596 static void buffer_sync_apple(struct wined3d_buffer *This, DWORD flags, const struct wined3d_gl_info *gl_info)
00597 {
00598     enum wined3d_event_query_result ret;
00599 
00600     /* No fencing needs to be done if the app promises not to overwrite
00601      * existing data */
00602     if(flags & WINED3DLOCK_NOOVERWRITE) return;
00603     if(flags & WINED3DLOCK_DISCARD)
00604     {
00605         ENTER_GL();
00606         GL_EXTCALL(glBufferDataARB(This->buffer_type_hint, This->resource.size, NULL, This->buffer_object_usage));
00607         checkGLcall("glBufferDataARB\n");
00608         LEAVE_GL();
00609         return;
00610     }
00611 
00612     if(!This->query)
00613     {
00614         TRACE("Creating event query for buffer %p\n", This);
00615 
00616         if (!wined3d_event_query_supported(gl_info))
00617         {
00618             FIXME("Event queries not supported, dropping async buffer locks.\n");
00619             goto drop_query;
00620         }
00621 
00622         This->query = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This->query));
00623         if (!This->query)
00624         {
00625             ERR("Failed to allocate event query memory, dropping async buffer locks.\n");
00626             goto drop_query;
00627         }
00628 
00629         /* Since we don't know about old draws a glFinish is needed once */
00630         wglFinish();
00631         return;
00632     }
00633     TRACE("Synchronizing buffer %p\n", This);
00634     ret = wined3d_event_query_finish(This->query, This->resource.device);
00635     switch(ret)
00636     {
00637         case WINED3D_EVENT_QUERY_NOT_STARTED:
00638         case WINED3D_EVENT_QUERY_OK:
00639             /* All done */
00640             return;
00641 
00642         case WINED3D_EVENT_QUERY_WRONG_THREAD:
00643             WARN("Cannot synchronize buffer lock due to a thread conflict\n");
00644             goto drop_query;
00645 
00646         default:
00647             ERR("wined3d_event_query_finish returned %u, dropping async buffer locks\n", ret);
00648             goto drop_query;
00649     }
00650 
00651 drop_query:
00652     if(This->query)
00653     {
00654         wined3d_event_query_destroy(This->query);
00655         This->query = NULL;
00656     }
00657 
00658     wglFinish();
00659     ENTER_GL();
00660     GL_EXTCALL(glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_TRUE));
00661     checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_TRUE)");
00662     LEAVE_GL();
00663     This->flags &= ~WINED3D_BUFFER_APPLESYNC;
00664 }
00665 
00666 /* The caller provides a GL context */
00667 static void buffer_direct_upload(struct wined3d_buffer *This, const struct wined3d_gl_info *gl_info, DWORD flags)
00668 {
00669     BYTE *map;
00670     UINT start = 0, len = 0;
00671 
00672     ENTER_GL();
00673 
00674     /* This potentially invalidates the element array buffer binding, but the
00675      * caller always takes care of this. */
00676     GL_EXTCALL(glBindBufferARB(This->buffer_type_hint, This->buffer_object));
00677     checkGLcall("glBindBufferARB");
00678     if (gl_info->supported[ARB_MAP_BUFFER_RANGE])
00679     {
00680         GLbitfield mapflags;
00681         mapflags = GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
00682         if (flags & WINED3D_BUFFER_DISCARD)
00683             mapflags |= GL_MAP_INVALIDATE_BUFFER_BIT;
00684         if (flags & WINED3D_BUFFER_NOSYNC)
00685             mapflags |= GL_MAP_UNSYNCHRONIZED_BIT;
00686         map = GL_EXTCALL(glMapBufferRange(This->buffer_type_hint, 0,
00687                     This->resource.size, mapflags));
00688         checkGLcall("glMapBufferRange");
00689     }
00690     else
00691     {
00692         if (This->flags & WINED3D_BUFFER_APPLESYNC)
00693         {
00694             DWORD syncflags = 0;
00695             if (flags & WINED3D_BUFFER_DISCARD) syncflags |= WINED3DLOCK_DISCARD;
00696             if (flags & WINED3D_BUFFER_NOSYNC) syncflags |= WINED3DLOCK_NOOVERWRITE;
00697             LEAVE_GL();
00698             buffer_sync_apple(This, syncflags, gl_info);
00699             ENTER_GL();
00700         }
00701         map = GL_EXTCALL(glMapBufferARB(This->buffer_type_hint, GL_WRITE_ONLY_ARB));
00702         checkGLcall("glMapBufferARB");
00703     }
00704     if (!map)
00705     {
00706         LEAVE_GL();
00707         ERR("Failed to map opengl buffer\n");
00708         return;
00709     }
00710 
00711     while (This->modified_areas)
00712     {
00713         This->modified_areas--;
00714         start = This->maps[This->modified_areas].offset;
00715         len = This->maps[This->modified_areas].size;
00716 
00717         memcpy(map + start, This->resource.allocatedMemory + start, len);
00718 
00719         if (gl_info->supported[ARB_MAP_BUFFER_RANGE])
00720         {
00721             GL_EXTCALL(glFlushMappedBufferRange(This->buffer_type_hint, start, len));
00722             checkGLcall("glFlushMappedBufferRange");
00723         }
00724         else if (This->flags & WINED3D_BUFFER_FLUSH)
00725         {
00726             GL_EXTCALL(glFlushMappedBufferRangeAPPLE(This->buffer_type_hint, start, len));
00727             checkGLcall("glFlushMappedBufferRangeAPPLE");
00728         }
00729     }
00730     GL_EXTCALL(glUnmapBufferARB(This->buffer_type_hint));
00731     checkGLcall("glUnmapBufferARB");
00732 
00733     LEAVE_GL();
00734 }
00735 
00736 /* Do not call while under the GL lock. */
00737 void CDECL wined3d_buffer_preload(struct wined3d_buffer *buffer)
00738 {
00739     DWORD flags = buffer->flags & (WINED3D_BUFFER_NOSYNC | WINED3D_BUFFER_DISCARD);
00740     struct wined3d_device *device = buffer->resource.device;
00741     UINT start = 0, end = 0, len = 0, vertices;
00742     const struct wined3d_gl_info *gl_info;
00743     struct wined3d_context *context;
00744     BOOL decl_changed = FALSE;
00745     unsigned int i, j;
00746     BYTE *data;
00747 
00748     TRACE("buffer %p.\n", buffer);
00749 
00750     buffer->flags &= ~(WINED3D_BUFFER_NOSYNC | WINED3D_BUFFER_DISCARD);
00751 
00752     if (!buffer->buffer_object)
00753     {
00754         /* TODO: Make converting independent from VBOs */
00755         if (buffer->flags & WINED3D_BUFFER_CREATEBO)
00756         {
00757             context = context_acquire(device, NULL);
00758             buffer_create_buffer_object(buffer, context->gl_info);
00759             context_release(context);
00760             buffer->flags &= ~WINED3D_BUFFER_CREATEBO;
00761         }
00762         else
00763         {
00764             /* Not doing any conversion */
00765             return;
00766         }
00767     }
00768 
00769     /* Reading the declaration makes only sense if the stateblock is finalized and the buffer bound to a stream */
00770     if (device->isInDraw && buffer->bind_count > 0)
00771     {
00772         decl_changed = buffer_find_decl(buffer);
00773         buffer->flags |= WINED3D_BUFFER_HASDESC;
00774     }
00775 
00776     if (!decl_changed && !(buffer->flags & WINED3D_BUFFER_HASDESC && buffer_is_dirty(buffer)))
00777     {
00778         ++buffer->draw_count;
00779         if (buffer->draw_count > VB_RESETDECLCHANGE)
00780             buffer->decl_change_count = 0;
00781         if (buffer->draw_count > VB_RESETFULLCONVS)
00782             buffer->full_conversion_count = 0;
00783         return;
00784     }
00785 
00786     /* If applications change the declaration over and over, reconverting all the time is a huge
00787      * performance hit. So count the declaration changes and release the VBO if there are too many
00788      * of them (and thus stop converting)
00789      */
00790     if (decl_changed)
00791     {
00792         ++buffer->decl_change_count;
00793         buffer->draw_count = 0;
00794 
00795         if (buffer->decl_change_count > VB_MAXDECLCHANGES
00796                 || (buffer->conversion_map && (buffer->resource.usage & WINED3DUSAGE_DYNAMIC)))
00797         {
00798             FIXME("Too many declaration changes or converting dynamic buffer, stopping converting\n");
00799 
00800             buffer_unload(&buffer->resource);
00801             buffer->flags &= ~WINED3D_BUFFER_CREATEBO;
00802 
00803             /* The stream source state handler might have read the memory of
00804              * the vertex buffer already and got the memory in the vbo which
00805              * is not valid any longer. Dirtify the stream source to force a
00806              * reload. This happens only once per changed vertexbuffer and
00807              * should occur rather rarely. */
00808             device_invalidate_state(device, STATE_STREAMSRC);
00809             return;
00810         }
00811 
00812         /* The declaration changed, reload the whole buffer */
00813         WARN("Reloading buffer because of decl change\n");
00814         buffer_clear_dirty_areas(buffer);
00815         if (!buffer_add_dirty_area(buffer, 0, 0))
00816         {
00817             ERR("buffer_add_dirty_area failed, this is not expected\n");
00818             return;
00819         }
00820         /* Avoid unfenced updates, we might overwrite more areas of the buffer than the application
00821          * cleared for unsynchronized updates
00822          */
00823         flags = 0;
00824     }
00825     else
00826     {
00827         /* However, it is perfectly fine to change the declaration every now and then. We don't want a game that
00828          * changes it every minute drop the VBO after VB_MAX_DECL_CHANGES minutes. So count draws without
00829          * decl changes and reset the decl change count after a specific number of them
00830          */
00831         if (buffer->conversion_map && buffer_is_fully_dirty(buffer))
00832         {
00833             ++buffer->full_conversion_count;
00834             if (buffer->full_conversion_count > VB_MAXFULLCONVERSIONS)
00835             {
00836                 FIXME("Too many full buffer conversions, stopping converting.\n");
00837                 buffer_unload(&buffer->resource);
00838                 buffer->flags &= ~WINED3D_BUFFER_CREATEBO;
00839                 if (buffer->bind_count)
00840                     device_invalidate_state(device, STATE_STREAMSRC);
00841                 return;
00842             }
00843         }
00844         else
00845         {
00846             ++buffer->draw_count;
00847             if (buffer->draw_count > VB_RESETDECLCHANGE)
00848                 buffer->decl_change_count = 0;
00849             if (buffer->draw_count > VB_RESETFULLCONVS)
00850                 buffer->full_conversion_count = 0;
00851         }
00852     }
00853 
00854     if (buffer->buffer_type_hint == GL_ELEMENT_ARRAY_BUFFER_ARB)
00855         device_invalidate_state(device, STATE_INDEXBUFFER);
00856 
00857     if (!buffer->conversion_map)
00858     {
00859         /* That means that there is nothing to fixup. Just upload from
00860          * buffer->resource.allocatedMemory directly into the vbo. Do not
00861          * free the system memory copy because drawPrimitive may need it if
00862          * the stride is 0, for instancing emulation, vertex blending
00863          * emulation or shader emulation. */
00864         TRACE("No conversion needed.\n");
00865 
00866         /* Nothing to do because we locked directly into the vbo */
00867         if (!(buffer->flags & WINED3D_BUFFER_DOUBLEBUFFER))
00868         {
00869             return;
00870         }
00871 
00872         context = context_acquire(device, NULL);
00873         buffer_direct_upload(buffer, context->gl_info, flags);
00874 
00875         context_release(context);
00876         return;
00877     }
00878 
00879     context = context_acquire(device, NULL);
00880     gl_info = context->gl_info;
00881 
00882     if(!(buffer->flags & WINED3D_BUFFER_DOUBLEBUFFER))
00883     {
00884         buffer_get_sysmem(buffer, gl_info);
00885     }
00886 
00887     /* Now for each vertex in the buffer that needs conversion */
00888     vertices = buffer->resource.size / buffer->stride;
00889 
00890     data = HeapAlloc(GetProcessHeap(), 0, buffer->resource.size);
00891 
00892     while(buffer->modified_areas)
00893     {
00894         buffer->modified_areas--;
00895         start = buffer->maps[buffer->modified_areas].offset;
00896         len = buffer->maps[buffer->modified_areas].size;
00897         end = start + len;
00898 
00899         memcpy(data + start, buffer->resource.allocatedMemory + start, end - start);
00900         for (i = start / buffer->stride; i < min((end / buffer->stride) + 1, vertices); ++i)
00901         {
00902             for (j = 0; j < buffer->stride; ++j)
00903             {
00904                 switch (buffer->conversion_map[j])
00905                 {
00906                     case CONV_NONE:
00907                         /* Done already */
00908                         j += 3;
00909                         break;
00910                     case CONV_D3DCOLOR:
00911                         fixup_d3dcolor((DWORD *) (data + i * buffer->stride + j));
00912                         j += 3;
00913                         break;
00914 
00915                     case CONV_POSITIONT:
00916                         fixup_transformed_pos((float *) (data + i * buffer->stride + j));
00917                         j += 15;
00918                         break;
00919                     default:
00920                         FIXME("Unimplemented conversion %d in shifted conversion\n", buffer->conversion_map[j]);
00921                 }
00922             }
00923         }
00924 
00925         ENTER_GL();
00926         GL_EXTCALL(glBindBufferARB(buffer->buffer_type_hint, buffer->buffer_object));
00927         checkGLcall("glBindBufferARB");
00928         GL_EXTCALL(glBufferSubDataARB(buffer->buffer_type_hint, start, len, data + start));
00929         checkGLcall("glBufferSubDataARB");
00930         LEAVE_GL();
00931     }
00932 
00933     HeapFree(GetProcessHeap(), 0, data);
00934     context_release(context);
00935 }
00936 
00937 static DWORD buffer_sanitize_flags(const struct wined3d_buffer *buffer, DWORD flags)
00938 {
00939     /* Not all flags make sense together, but Windows never returns an error. Catch the
00940      * cases that could cause issues */
00941     if(flags & WINED3DLOCK_READONLY)
00942     {
00943         if(flags & WINED3DLOCK_DISCARD)
00944         {
00945             WARN("WINED3DLOCK_READONLY combined with WINED3DLOCK_DISCARD, ignoring flags\n");
00946             return 0;
00947         }
00948         if(flags & WINED3DLOCK_NOOVERWRITE)
00949         {
00950             WARN("WINED3DLOCK_READONLY combined with WINED3DLOCK_NOOVERWRITE, ignoring flags\n");
00951             return 0;
00952         }
00953     }
00954     else if((flags & (WINED3DLOCK_DISCARD | WINED3DLOCK_NOOVERWRITE)) == (WINED3DLOCK_DISCARD | WINED3DLOCK_NOOVERWRITE))
00955     {
00956         WARN("WINED3DLOCK_DISCARD and WINED3DLOCK_NOOVERWRITE used together, ignoring\n");
00957         return 0;
00958     }
00959     else if (flags & (WINED3DLOCK_DISCARD | WINED3DLOCK_NOOVERWRITE) && !(buffer->resource.usage & WINED3DUSAGE_DYNAMIC))
00960     {
00961         WARN("DISCARD or NOOVERWRITE lock on non-dynamic buffer, ignoring\n");
00962         return 0;
00963     }
00964 
00965     return flags;
00966 }
00967 
00968 static GLbitfield buffer_gl_map_flags(DWORD d3d_flags)
00969 {
00970     GLbitfield ret = 0;
00971 
00972     if (!(d3d_flags & WINED3DLOCK_READONLY))
00973         ret |= GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
00974     if (!(d3d_flags & (WINED3DLOCK_DISCARD | WINED3DLOCK_NOOVERWRITE)))
00975         ret |= GL_MAP_READ_BIT;
00976 
00977     if (d3d_flags & WINED3DLOCK_DISCARD)
00978         ret |= GL_MAP_INVALIDATE_BUFFER_BIT;
00979     if (d3d_flags & WINED3DLOCK_NOOVERWRITE)
00980         ret |= GL_MAP_UNSYNCHRONIZED_BIT;
00981 
00982     return ret;
00983 }
00984 
00985 struct wined3d_resource * CDECL wined3d_buffer_get_resource(struct wined3d_buffer *buffer)
00986 {
00987     TRACE("buffer %p.\n", buffer);
00988 
00989     return &buffer->resource;
00990 }
00991 
00992 HRESULT CDECL wined3d_buffer_map(struct wined3d_buffer *buffer, UINT offset, UINT size, BYTE **data, DWORD flags)
00993 {
00994     BOOL dirty = buffer_is_dirty(buffer);
00995     LONG count;
00996 
00997     TRACE("buffer %p, offset %u, size %u, data %p, flags %#x\n", buffer, offset, size, data, flags);
00998 
00999     flags = buffer_sanitize_flags(buffer, flags);
01000     if (!(flags & WINED3DLOCK_READONLY))
01001     {
01002         if (!buffer_add_dirty_area(buffer, offset, size)) return E_OUTOFMEMORY;
01003     }
01004 
01005     count = InterlockedIncrement(&buffer->lock_count);
01006 
01007     if (buffer->buffer_object)
01008     {
01009         if (!(buffer->flags & WINED3D_BUFFER_DOUBLEBUFFER))
01010         {
01011             if (count == 1)
01012             {
01013                 struct wined3d_device *device = buffer->resource.device;
01014                 struct wined3d_context *context;
01015                 const struct wined3d_gl_info *gl_info;
01016 
01017                 context = context_acquire(device, NULL);
01018                 gl_info = context->gl_info;
01019 
01020                 ENTER_GL();
01021 
01022                 if (buffer->buffer_type_hint == GL_ELEMENT_ARRAY_BUFFER_ARB)
01023                     context_invalidate_state(context, STATE_INDEXBUFFER);
01024                 GL_EXTCALL(glBindBufferARB(buffer->buffer_type_hint, buffer->buffer_object));
01025 
01026                 if (gl_info->supported[ARB_MAP_BUFFER_RANGE])
01027                 {
01028                     GLbitfield mapflags = buffer_gl_map_flags(flags);
01029                     buffer->resource.allocatedMemory = GL_EXTCALL(glMapBufferRange(buffer->buffer_type_hint,
01030                             0, buffer->resource.size, mapflags));
01031                     checkGLcall("glMapBufferRange");
01032                 }
01033                 else
01034                 {
01035                     if (buffer->flags & WINED3D_BUFFER_APPLESYNC)
01036                     {
01037                         LEAVE_GL();
01038                         buffer_sync_apple(buffer, flags, gl_info);
01039                         ENTER_GL();
01040                     }
01041                     buffer->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(buffer->buffer_type_hint,
01042                             GL_READ_WRITE_ARB));
01043                     checkGLcall("glMapBufferARB");
01044                 }
01045                 LEAVE_GL();
01046 
01047                 if (((DWORD_PTR)buffer->resource.allocatedMemory) & (RESOURCE_ALIGNMENT - 1))
01048                 {
01049                     WARN("Pointer %p is not %u byte aligned.\n", buffer->resource.allocatedMemory, RESOURCE_ALIGNMENT);
01050 
01051                     ENTER_GL();
01052                     GL_EXTCALL(glUnmapBufferARB(buffer->buffer_type_hint));
01053                     checkGLcall("glUnmapBufferARB");
01054                     LEAVE_GL();
01055                     buffer->resource.allocatedMemory = NULL;
01056 
01057                     if (buffer->resource.usage & WINED3DUSAGE_DYNAMIC)
01058                     {
01059                         /* The extra copy is more expensive than not using VBOs at
01060                          * all on the Nvidia Linux driver, which is the only driver
01061                          * that returns unaligned pointers
01062                          */
01063                         TRACE("Dynamic buffer, dropping VBO\n");
01064                         buffer_unload(&buffer->resource);
01065                         buffer->flags &= ~WINED3D_BUFFER_CREATEBO;
01066                         if (buffer->bind_count)
01067                             device_invalidate_state(device, STATE_STREAMSRC);
01068                     }
01069                     else
01070                     {
01071                         TRACE("Falling back to doublebuffered operation\n");
01072                         buffer_get_sysmem(buffer, gl_info);
01073                     }
01074                     TRACE("New pointer is %p.\n", buffer->resource.allocatedMemory);
01075                 }
01076                 context_release(context);
01077             }
01078         }
01079         else
01080         {
01081             if (dirty)
01082             {
01083                 if (buffer->flags & WINED3D_BUFFER_NOSYNC && !(flags & WINED3DLOCK_NOOVERWRITE))
01084                 {
01085                     buffer->flags &= ~WINED3D_BUFFER_NOSYNC;
01086                 }
01087             }
01088             else if(flags & WINED3DLOCK_NOOVERWRITE)
01089             {
01090                 buffer->flags |= WINED3D_BUFFER_NOSYNC;
01091             }
01092 
01093             if (flags & WINED3DLOCK_DISCARD)
01094             {
01095                 buffer->flags |= WINED3D_BUFFER_DISCARD;
01096             }
01097         }
01098     }
01099 
01100     *data = buffer->resource.allocatedMemory + offset;
01101 
01102     TRACE("Returning memory at %p (base %p, offset %u).\n", *data, buffer->resource.allocatedMemory, offset);
01103     /* TODO: check Flags compatibility with buffer->currentDesc.Usage (see MSDN) */
01104 
01105     return WINED3D_OK;
01106 }
01107 
01108 void CDECL wined3d_buffer_unmap(struct wined3d_buffer *buffer)
01109 {
01110     ULONG i;
01111 
01112     TRACE("buffer %p.\n", buffer);
01113 
01114     /* In the case that the number of Unmap calls > the
01115      * number of Map calls, d3d returns always D3D_OK.
01116      * This is also needed to prevent Map from returning garbage on
01117      * the next call (this will happen if the lock_count is < 0). */
01118     if (!buffer->lock_count)
01119     {
01120         WARN("Unmap called without a previous map call.\n");
01121         return;
01122     }
01123 
01124     if (InterlockedDecrement(&buffer->lock_count))
01125     {
01126         /* Delay loading the buffer until everything is unlocked */
01127         TRACE("Ignoring unmap.\n");
01128         return;
01129     }
01130 
01131     if (!(buffer->flags & WINED3D_BUFFER_DOUBLEBUFFER) && buffer->buffer_object)
01132     {
01133         struct wined3d_device *device = buffer->resource.device;
01134         const struct wined3d_gl_info *gl_info;
01135         struct wined3d_context *context;
01136 
01137         context = context_acquire(device, NULL);
01138         gl_info = context->gl_info;
01139 
01140         ENTER_GL();
01141 
01142         if (buffer->buffer_type_hint == GL_ELEMENT_ARRAY_BUFFER_ARB)
01143             context_invalidate_state(context, STATE_INDEXBUFFER);
01144         GL_EXTCALL(glBindBufferARB(buffer->buffer_type_hint, buffer->buffer_object));
01145 
01146         if (gl_info->supported[ARB_MAP_BUFFER_RANGE])
01147         {
01148             for (i = 0; i < buffer->modified_areas; ++i)
01149             {
01150                 GL_EXTCALL(glFlushMappedBufferRange(buffer->buffer_type_hint,
01151                         buffer->maps[i].offset, buffer->maps[i].size));
01152                 checkGLcall("glFlushMappedBufferRange");
01153             }
01154         }
01155         else if (buffer->flags & WINED3D_BUFFER_FLUSH)
01156         {
01157             for (i = 0; i < buffer->modified_areas; ++i)
01158             {
01159                 GL_EXTCALL(glFlushMappedBufferRangeAPPLE(buffer->buffer_type_hint,
01160                         buffer->maps[i].offset, buffer->maps[i].size));
01161                 checkGLcall("glFlushMappedBufferRangeAPPLE");
01162             }
01163         }
01164 
01165         GL_EXTCALL(glUnmapBufferARB(buffer->buffer_type_hint));
01166         LEAVE_GL();
01167         if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
01168         context_release(context);
01169 
01170         buffer->resource.allocatedMemory = NULL;
01171         buffer_clear_dirty_areas(buffer);
01172     }
01173     else if (buffer->flags & WINED3D_BUFFER_HASDESC)
01174     {
01175         wined3d_buffer_preload(buffer);
01176     }
01177 }
01178 
01179 static const struct wined3d_resource_ops buffer_resource_ops =
01180 {
01181     buffer_unload,
01182 };
01183 
01184 static HRESULT buffer_init(struct wined3d_buffer *buffer, struct wined3d_device *device,
01185         UINT size, DWORD usage, enum wined3d_format_id format_id, enum wined3d_pool pool, GLenum bind_hint,
01186         const char *data, void *parent, const struct wined3d_parent_ops *parent_ops)
01187 {
01188     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
01189     const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
01190     HRESULT hr;
01191     BOOL dynamic_buffer_ok;
01192 
01193     if (!size)
01194     {
01195         WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
01196         return WINED3DERR_INVALIDCALL;
01197     }
01198 
01199     hr = resource_init(&buffer->resource, device, WINED3D_RTYPE_BUFFER, format,
01200             WINED3D_MULTISAMPLE_NONE, 0, usage, pool, size, 1, 1, size,
01201             parent, parent_ops, &buffer_resource_ops);
01202     if (FAILED(hr))
01203     {
01204         WARN("Failed to initialize resource, hr %#x\n", hr);
01205         return hr;
01206     }
01207     buffer->buffer_type_hint = bind_hint;
01208 
01209     TRACE("size %#x, usage %#x, format %s, memory @ %p, iface @ %p.\n", buffer->resource.size, buffer->resource.usage,
01210             debug_d3dformat(buffer->resource.format->id), buffer->resource.allocatedMemory, buffer);
01211 
01212     dynamic_buffer_ok = gl_info->supported[APPLE_FLUSH_BUFFER_RANGE] || gl_info->supported[ARB_MAP_BUFFER_RANGE];
01213 
01214     /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
01215      * drawStridedFast (half-life 2 and others).
01216      *
01217      * Basically converting the vertices in the buffer is quite expensive, and observations
01218      * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
01219      * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
01220      */
01221     if (!gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
01222     {
01223         TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
01224     }
01225     else if(buffer->resource.pool == WINED3D_POOL_SYSTEM_MEM)
01226     {
01227         TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
01228     }
01229     else if(!dynamic_buffer_ok && (buffer->resource.usage & WINED3DUSAGE_DYNAMIC))
01230     {
01231         TRACE("Not creating a vbo because the buffer has dynamic usage and no GL support\n");
01232     }
01233     else
01234     {
01235         buffer->flags |= WINED3D_BUFFER_CREATEBO;
01236     }
01237 
01238     if (data)
01239     {
01240         BYTE *ptr;
01241 
01242         hr = wined3d_buffer_map(buffer, 0, size, &ptr, 0);
01243         if (FAILED(hr))
01244         {
01245             ERR("Failed to map buffer, hr %#x\n", hr);
01246             buffer_unload(&buffer->resource);
01247             resource_cleanup(&buffer->resource);
01248             return hr;
01249         }
01250 
01251         memcpy(ptr, data, size);
01252 
01253         wined3d_buffer_unmap(buffer);
01254     }
01255 
01256     buffer->maps = HeapAlloc(GetProcessHeap(), 0, sizeof(*buffer->maps));
01257     if (!buffer->maps)
01258     {
01259         ERR("Out of memory\n");
01260         buffer_unload(&buffer->resource);
01261         resource_cleanup(&buffer->resource);
01262         return E_OUTOFMEMORY;
01263     }
01264     buffer->maps_size = 1;
01265 
01266     return WINED3D_OK;
01267 }
01268 
01269 HRESULT CDECL wined3d_buffer_create(struct wined3d_device *device, struct wined3d_buffer_desc *desc, const void *data,
01270         void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
01271 {
01272     struct wined3d_buffer *object;
01273     HRESULT hr;
01274 
01275     TRACE("device %p, desc %p, data %p, parent %p, buffer %p\n", device, desc, data, parent, buffer);
01276 
01277     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
01278     if (!object)
01279     {
01280         ERR("Failed to allocate memory\n");
01281         return E_OUTOFMEMORY;
01282     }
01283 
01284     FIXME("Ignoring access flags (pool)\n");
01285 
01286     hr = buffer_init(object, device, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
01287             WINED3D_POOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
01288     if (FAILED(hr))
01289     {
01290         WARN("Failed to initialize buffer, hr %#x.\n", hr);
01291         HeapFree(GetProcessHeap(), 0, object);
01292         return hr;
01293     }
01294     object->desc = *desc;
01295 
01296     TRACE("Created buffer %p.\n", object);
01297 
01298     *buffer = object;
01299 
01300     return WINED3D_OK;
01301 }
01302 
01303 HRESULT CDECL wined3d_buffer_create_vb(struct wined3d_device *device, UINT size, DWORD usage, enum wined3d_pool pool,
01304         void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
01305 {
01306     struct wined3d_buffer *object;
01307     HRESULT hr;
01308 
01309     TRACE("device %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
01310             device, size, usage, pool, parent, parent_ops, buffer);
01311 
01312     if (pool == WINED3D_POOL_SCRATCH)
01313     {
01314         /* The d3d9 tests shows that this is not allowed. It doesn't make much
01315          * sense anyway, SCRATCH buffers wouldn't be usable anywhere. */
01316         WARN("Vertex buffer in WINED3D_POOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL.\n");
01317         *buffer = NULL;
01318         return WINED3DERR_INVALIDCALL;
01319     }
01320 
01321     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
01322     if (!object)
01323     {
01324         ERR("Out of memory\n");
01325         *buffer = NULL;
01326         return WINED3DERR_OUTOFVIDEOMEMORY;
01327     }
01328 
01329     hr = buffer_init(object, device, size, usage, WINED3DFMT_VERTEXDATA,
01330             pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
01331     if (FAILED(hr))
01332     {
01333         WARN("Failed to initialize buffer, hr %#x.\n", hr);
01334         HeapFree(GetProcessHeap(), 0, object);
01335         return hr;
01336     }
01337 
01338     TRACE("Created buffer %p.\n", object);
01339     *buffer = object;
01340 
01341     return WINED3D_OK;
01342 }
01343 
01344 HRESULT CDECL wined3d_buffer_create_ib(struct wined3d_device *device, UINT size, DWORD usage, enum wined3d_pool pool,
01345         void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_buffer **buffer)
01346 {
01347     struct wined3d_buffer *object;
01348     HRESULT hr;
01349 
01350     TRACE("device %p, size %u, usage %#x, pool %#x, parent %p, parent_ops %p, buffer %p.\n",
01351             device, size, usage, pool, parent, parent_ops, buffer);
01352 
01353     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
01354     if (!object)
01355     {
01356         ERR("Out of memory\n");
01357         *buffer = NULL;
01358         return WINED3DERR_OUTOFVIDEOMEMORY;
01359     }
01360 
01361     hr = buffer_init(object, device, size, usage | WINED3DUSAGE_STATICDECL,
01362             WINED3DFMT_UNKNOWN, pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
01363             parent, parent_ops);
01364     if (FAILED(hr))
01365     {
01366         WARN("Failed to initialize buffer, hr %#x\n", hr);
01367         HeapFree(GetProcessHeap(), 0, object);
01368         return hr;
01369     }
01370 
01371     TRACE("Created buffer %p.\n", object);
01372     *buffer = object;
01373 
01374     return WINED3D_OK;
01375 }

Generated on Fri May 25 2012 04:19:30 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.