buffer.c revision 3a343ca21a267ec3c54e2317e2ed18fe99b8ebbb
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * Copyright 2002-2005 Jason Edmeades
db9f3e3a2d6101381d3375a9ceb22a1f243f2284vboxsync * Copyright 2002-2005 Raphael Junqueira
db9f3e3a2d6101381d3375a9ceb22a1f243f2284vboxsync * Copyright 2004 Christian Costa
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * Copyright 2005 Oliver Stieber
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * Copyright 2007-2010 Stefan Dösinger for CodeWeavers
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * Copyright 2009 Henri Verbeet for CodeWeavers
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * This library is free software; you can redistribute it and/or
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * modify it under the terms of the GNU Lesser General Public
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * License as published by the Free Software Foundation; either
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * version 2.1 of the License, or (at your option) any later version.
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * This library is distributed in the hope that it will be useful,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * but WITHOUT ANY WARRANTY; without even the implied warranty of
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * Lesser General Public License for more details.
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * You should have received a copy of the GNU Lesser General Public
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * License along with this library; if not, write to the Free Software
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * a choice of LGPL license versions is made available with the language indicating
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * that LGPLv2 or any later version may be used, or where a choice of which version
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * of the LGPL is applied is otherwise unspecified.
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync#define GLINFO_LOCATION This->resource.device->adapter->gl_info
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync#define VB_MAXDECLCHANGES 100 /* After that number of decl changes we stop converting */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync#define VB_RESETDECLCHANGE 1000 /* Reset the decl changecount after that number of draws */
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync#define VB_MAXFULLCONVERSIONS 5 /* Number of full conversions before we stop converting */
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync#define VB_RESETFULLCONVS 20 /* Reset full conversion counts after that number of draws */
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsyncstatic inline BOOL buffer_add_dirty_area(struct wined3d_buffer *This, UINT offset, UINT size)
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync void *new = HeapReAlloc(GetProcessHeap(), 0, This->maps,
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync if(offset > This->resource.size || offset + size > This->resource.size)
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync WARN("Invalid range dirtified, marking entire buffer dirty\n");
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsyncstatic inline void buffer_clear_dirty_areas(struct wined3d_buffer *This)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsyncstatic inline BOOL buffer_is_dirty(struct wined3d_buffer *This)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsyncstatic inline BOOL buffer_is_fully_dirty(struct wined3d_buffer *This)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync unsigned int i;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync if(This->maps[i].offset == 0 && This->maps[i].size == This->resource.size)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync/* Context activation is done by the caller */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsyncstatic void delete_gl_buffer(struct wined3d_buffer *This)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync GL_EXTCALL(glDeleteBuffersARB(1, &This->buffer_object));
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync/* Context activation is done by the caller. */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsyncstatic void buffer_create_buffer_object(struct wined3d_buffer *This)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n",
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync /* Make sure that the gl error is cleared. Do not use checkGLcall
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * here because checkGLcall just prints a fixme and continues. However,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * if an error during VBO creation occurs we can fall back to non-vbo operation
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * with full functionality(but performance loss)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync /* Basically the FVF parameter passed to CreateVertexBuffer is no good
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * to check if the rhw and color values are in the correct format.
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync GL_EXTCALL(glGenBuffersARB(1, &This->buffer_object));
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync ERR("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync if(This->buffer_type_hint == GL_ELEMENT_ARRAY_BUFFER_ARB)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync IWineD3DDeviceImpl_MarkStateDirty(This->resource.device, STATE_INDEXBUFFER);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync GL_EXTCALL(glBindBufferARB(This->buffer_type_hint, This->buffer_object));
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync ERR("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync /* Don't use static, because dx apps tend to update the buffer
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * quite often even if they specify 0 usage.
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync GL_EXTCALL(glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE));
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE)");
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync GL_EXTCALL(glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE));
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE)");
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync /* No setup is needed here for GL_ARB_map_buffer_range */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync /* Reserve memory for the buffer. The amount of data won't change
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * so we are safe with calling glBufferData once and
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * calling glBufferSubData on updates. Upload the actual data in case
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * we're not double buffering, so we can release the heap mem afterwards
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync GL_EXTCALL(glBufferDataARB(This->buffer_type_hint, This->resource.size, This->resource.allocatedMemory, gl_usage));
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync ERR("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync ERR("buffer_add_dirty_area failed, this is not expected\n");
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync /* Clean up all vbo init, but continue because we can work without a vbo :-) */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync ERR("Failed to create a vertex buffer object. Continuing, but performance issues may occur\n");
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsyncstatic BOOL buffer_process_converted_attribute(struct wined3d_buffer *This,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync const enum wined3d_buffer_conversion_type conversion_type,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync const struct wined3d_stream_info_element *attrib, DWORD *stride_this_run)
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync unsigned int i;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync DWORD offset = This->resource.device->stateBlock->streamOffset[attrib->stream_idx];
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync /* Check for some valid situations which cause us pain. One is if the buffer is used for
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * constant attributes(stride = 0), the other one is if the buffer is used on two streams
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * with different strides. In the 2nd case we might have to drop conversion entirely,
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * it is possible that the same bytes are once read as FLOAT2 and once as UBYTE4N.
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync FIXME("%s used with stride 0, let's hope we get the vertex stride from somewhere else\n",
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync else if(attrib->stride != *stride_this_run && *stride_this_run)
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync FIXME("Got two concurrent strides, %d and %d\n", attrib->stride, *stride_this_run);
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync /* We rely that this happens only on the first converted attribute that is found,
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * if at all. See above check
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync TRACE("Reconverting because converted attributes occur, and the stride changed\n");
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, This->conversion_map);
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync This->conversion_map = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync data = (((DWORD_PTR)attrib->data) + offset) % This->stride;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync attrib_size = attrib->format_desc->component_count * attrib->format_desc->component_size;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync for (i = 0; i < attrib_size; ++i)
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync TRACE("It was type %d, is %d now\n", This->conversion_map[idx], conversion_type);
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsyncstatic BOOL buffer_check_attribute(struct wined3d_buffer *This, const struct wined3d_stream_info *si,
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync UINT attrib_idx, const BOOL check_d3dcolor, const BOOL is_ffp_position, const BOOL is_ffp_color,
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync const struct wined3d_stream_info_element *attrib = &si->elements[attrib_idx];
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync IWineD3DDeviceImpl *device = This->resource.device;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync /* Ignore attributes that do not have our vbo. After that check we can be sure that the attribute is
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * there, on nonexistent attribs the vbo is 0.
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync /* Look for newly appeared conversion */
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync && (format == WINED3DFMT_R16G16_FLOAT || format == WINED3DFMT_R16G16B16A16_FLOAT))
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync ret = buffer_process_converted_attribute(This, CONV_FLOAT16_2, attrib, stride_this_run);
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync if (is_ffp_position) FIXME("Test FLOAT16 fixed function processing positions\n");
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync else if (is_ffp_color) FIXME("test FLOAT16 fixed function processing colors\n");
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync else if (check_d3dcolor && format == WINED3DFMT_B8G8R8A8_UNORM)
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync ret = buffer_process_converted_attribute(This, CONV_D3DCOLOR, attrib, stride_this_run);
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync if (!is_ffp_color) FIXME("Test for non-color fixed function WINED3DFMT_B8G8R8A8_UNORM format\n");
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync else if (is_ffp_position && format == WINED3DFMT_R32G32B32A32_FLOAT)
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync ret = buffer_process_converted_attribute(This, CONV_POSITIONT, attrib, stride_this_run);
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync ret = buffer_process_converted_attribute(This, CONV_NONE, attrib, stride_this_run);
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsyncstatic UINT *find_conversion_shift(struct wined3d_buffer *This,
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync const struct wined3d_stream_info *strided, UINT stride)
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DWORD) * stride);
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync for (i = 0; i < MAX_ATTRIBS; ++i)
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync if (!(strided->use_map & (1 << i)) || strided->elements[i].buffer_object != This->buffer_object) continue;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync /* Pre-shift the last 4 bytes in the FLOAT16_4 by 4 bytes - this makes FLOAT16_2 and FLOAT16_4 conversions
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * compatible
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync ret[(DWORD_PTR)strided->elements[i].data + j] += 4;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync orig_type_size = strided->elements[i].format_desc->component_count
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * strided->elements[i].format_desc->component_size;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync for (j = (DWORD_PTR)strided->elements[i].data + orig_type_size; j < stride; ++j)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync for (i = 0; i < stride; ++i)
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsyncstatic BOOL buffer_find_decl(struct wined3d_buffer *This)
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync IWineD3DDeviceImpl *device = This->resource.device;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync const struct wined3d_stream_info *si = &device->strided_streams;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync unsigned int i;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync /* In d3d7 the vertex buffer declaration NEVER changes because it is stored in the d3d7 vertex buffer.
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * Once we have our declaration there is no need to look it up again. Index buffers also never need
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * conversion, so once the (empty) conversion structure is created don't bother checking again
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync if(This->resource.usage & WINED3DUSAGE_STATICDECL) return FALSE;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync TRACE("Finding vertex buffer conversion information\n");
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync /* Certain declaration types need some fixups before we can pass them to
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * opengl. This means D3DCOLOR attributes with fixed function vertex
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * processing, FLOAT4 POSITIONT with fixed function, and FLOAT16 if
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * GL_ARB_half_float_vertex is not supported.
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * Note for d3d8 and d3d9:
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * The vertex buffer FVF doesn't help with finding them, we have to use
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * the decoded vertex declaration and pick the things that concern the
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * current buffer. A problem with this is that this can change between
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * draws, so we have to validate the information and reprocess the buffer
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * if it changes, and avoid false positives for performance reasons.
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * WineD3D doesn't even know the vertex buffer any more, it is managed
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * by the client libraries and passed to SetStreamSource and ProcessVertices
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * as needed.
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * We have to distinguish between vertex shaders and fixed function to
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * pick the way we access the strided vertex information.
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * This code sets up a per-byte array with the size of the detected
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * stride of the arrays in the buffer. For each byte we have a field
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * that marks the conversion needed on this byte. For example, the
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * following declaration with fixed function vertex processing:
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * POSITIONT, FLOAT4
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * NORMAL, FLOAT3
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * DIFFUSE, FLOAT16_4
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * SPECULAR, D3DCOLOR
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * Will result in
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * { POSITIONT }{ NORMAL }{ DIFFUSE }{SPECULAR }
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * [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]
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * Where in this example map P means 4 component position conversion, 0
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * means no conversion, F means FLOAT16_2 conversion and C means D3DCOLOR
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * conversion (red / blue swizzle).
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * If we're doing conversion and the stride changes we have to reconvert
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * the whole buffer. Note that we do not mind if the semantic changes,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * we only care for the conversion type. So if the NORMAL is replaced
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * with a TEXCOORD, nothing has to be done, or if the DIFFUSE is replaced
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * with a D3DCOLOR BLENDWEIGHT we can happily dismiss the change. Some
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * conversion types depend on the semantic as well, for example a FLOAT4
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * texcoord needs no conversion while a FLOAT4 positiont needs one
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync /* If the current vertex declaration is marked for no half float conversion don't bother to
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * analyse the strided streams in depth, just set them up for no conversion. Return decl changed
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * if we used conversion before
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync if (!((IWineD3DVertexDeclarationImpl *) device->stateBlock->vertexDecl)->half_float_conv_needed)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRACE("Now using shaders without conversion, but conversion used before\n");
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync HeapFree(GetProcessHeap(), 0, This->conversion_map);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync HeapFree(GetProcessHeap(), 0, This->conversion_shift);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync for (i = 0; i < MAX_ATTRIBS; ++i)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync ret = buffer_check_attribute(This, si, i, FALSE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync /* Recalculate the conversion shift map if the declaration has changed,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * and we're using float16 conversion or used it on the last run
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync HeapFree(GetProcessHeap(), 0, This->conversion_shift);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync This->conversion_shift = find_conversion_shift(This, si, This->stride);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync /* Fixed function is a bit trickier. We have to take care for D3DCOLOR types, FLOAT4 positions and of course
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * FLOAT16s if not supported. Also, we can't iterate over the array, so use macros to generate code for all
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * the attributes that our current fixed function pipeline implementation cares for.
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync BOOL support_d3dcolor = gl_info->supported[ARB_VERTEX_ARRAY_BGRA];
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync ret = buffer_check_attribute(This, si, WINED3D_FFP_POSITION,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRUE, TRUE, FALSE, &stride_this_run, &float16_used) || ret;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync ret = buffer_check_attribute(This, si, WINED3D_FFP_NORMAL,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync ret = buffer_check_attribute(This, si, WINED3D_FFP_DIFFUSE,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync !support_d3dcolor, FALSE, TRUE, &stride_this_run, &float16_used) || ret;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync ret = buffer_check_attribute(This, si, WINED3D_FFP_SPECULAR,
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync !support_d3dcolor, FALSE, TRUE, &stride_this_run, &float16_used) || ret;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD0,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD1,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD2,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD3,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD4,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD5,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD6,
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync ret = buffer_check_attribute(This, si, WINED3D_FFP_TEXCOORD7,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync if (float16_used) FIXME("Float16 conversion used with fixed function vertex processing\n");
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync /* Sanity test */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync if (!ret) ERR("no converted attributes found, old conversion map exists, and no declaration change?\n");
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync HeapFree(GetProcessHeap(), 0, This->conversion_map);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync if (ret) TRACE("Conversion information changed\n");
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync/* Context activation is done by the caller. */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsyncstatic void buffer_check_buffer_object_size(struct wined3d_buffer *This)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync This->conversion_stride * (This->resource.size / This->stride) : This->resource.size;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRACE("Old size %u, creating new size %u\n", This->buffer_object_size, size);
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync if(This->buffer_type_hint == GL_ELEMENT_ARRAY_BUFFER_ARB)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync IWineD3DDeviceImpl_MarkStateDirty(This->resource.device, STATE_INDEXBUFFER);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync /* Rescue the data before resizing the buffer object if we do not have our backup copy */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync GL_EXTCALL(glBindBufferARB(This->buffer_type_hint, This->buffer_object));
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync GL_EXTCALL(glBufferDataARB(This->buffer_type_hint, size, NULL, This->buffer_object_usage));
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync /* Color conversion like in drawStridedSlow. watch out for little endianity
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * If we want that stuff to work on big endian machines too we have to consider more things
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync * 0xff000000: Alpha mask
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * 0x00ff0000: Blue mask
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * 0x0000ff00: Green mask
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync * 0x000000ff: Red mask
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync *dst_color |= (src_color & 0xff00ff00); /* Alpha Green */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync *dst_color |= (src_color & 0x00ff0000) >> 16; /* Red */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync *dst_color |= (src_color & 0x000000ff) << 16; /* Blue */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsyncstatic inline void fixup_transformed_pos(float *p)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync /* rhw conversion like in position_float4(). */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync/* Context activation is done by the caller. */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsyncconst BYTE *buffer_get_memory(IWineD3DBuffer *iface, GLuint *buffer_object)
07557d07616212d7ba6e7ab3059e85cb14633775vboxsync struct wined3d_buffer *This = (struct wined3d_buffer *)iface;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync/* IUnknown methods */
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsyncstatic HRESULT STDMETHODCALLTYPE buffer_QueryInterface(IWineD3DBuffer *iface,
0b6a21892fd667342bd302336bc327e93e365bdavboxsync TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsyncstatic ULONG STDMETHODCALLTYPE buffer_AddRef(IWineD3DBuffer *iface)
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync struct wined3d_buffer *This = (struct wined3d_buffer *)iface;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync ULONG refcount = InterlockedIncrement(&This->resource.ref);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRACE("%p increasing refcount to %u\n", This, refcount);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync/* Context activation is done by the caller. */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsyncBYTE *buffer_get_sysmem(struct wined3d_buffer *This)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync /* AllocatedMemory exists if the buffer is double buffered or has no buffer object at all */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync if(This->resource.allocatedMemory) return This->resource.allocatedMemory;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync This->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size + RESOURCE_ALIGNMENT);
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync This->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync GL_EXTCALL(glBindBufferARB(This->buffer_type_hint, This->buffer_object));
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync GL_EXTCALL(glGetBufferSubDataARB(This->buffer_type_hint, 0, This->resource.size, This->resource.allocatedMemory));
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsyncstatic void STDMETHODCALLTYPE buffer_UnLoad(IWineD3DBuffer *iface)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync struct wined3d_buffer *This = (struct wined3d_buffer *)iface;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync IWineD3DDeviceImpl *device = This->resource.device;
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync /* Download the buffer, but don't permanently enable double buffering */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync This->flags |= WINED3D_BUFFER_CREATEBO; /* Recreate the buffer object next load */
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsync HeapFree(GetProcessHeap(), 0, This->conversion_shift);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync HeapFree(GetProcessHeap(), 0, This->conversion_map);
29c524c419977a7018139c3db3d4cb39dd63c408vboxsyncstatic ULONG STDMETHODCALLTYPE buffer_Release(IWineD3DBuffer *iface)
29c524c419977a7018139c3db3d4cb39dd63c408vboxsync struct wined3d_buffer *This = (struct wined3d_buffer *)iface;
29c524c419977a7018139c3db3d4cb39dd63c408vboxsync ULONG refcount = InterlockedDecrement(&This->resource.ref);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync TRACE("%p decreasing refcount to %u\n", This, refcount);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync This->resource.parent_ops->wined3d_object_destroyed(This->resource.parent);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync/* IWineD3DBase methods */
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsyncstatic HRESULT STDMETHODCALLTYPE buffer_GetParent(IWineD3DBuffer *iface, IUnknown **parent)
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync return resource_get_parent((IWineD3DResource *)iface, parent);
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync/* IWineD3DResource methods */
ed144bee38a6c8b914d3f027f1c118a2b0482d4fvboxsyncstatic HRESULT STDMETHODCALLTYPE buffer_SetPrivateData(IWineD3DBuffer *iface,
930b5f872e89407f445d4000d4e4aaecaa6a0998vboxsync REFGUID guid, const void *data, DWORD data_size, DWORD flags)
static void buffer_sync_apple(struct wined3d_buffer *This, DWORD flags, const struct wined3d_gl_info *gl_info)
ENTER_GL();
GL_EXTCALL(glBufferDataARB(This->buffer_type_hint, This->resource.size, NULL, This->buffer_object_usage));
LEAVE_GL();
goto drop_query;
goto drop_query;
wglFinish();
switch(ret)
case WINED3D_EVENT_QUERY_OK:
goto drop_query;
goto drop_query;
wglFinish();
ENTER_GL();
GL_EXTCALL(glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_TRUE));
checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_TRUE)");
LEAVE_GL();
static void buffer_direct_upload(struct wined3d_buffer *This, const struct wined3d_gl_info *gl_info, DWORD flags)
ENTER_GL();
LEAVE_GL();
ENTER_GL();
if (!map)
LEAVE_GL();
LEAVE_GL();
goto end;
/* Reading the declaration makes only sense if the stateblock is finalized and the buffer bound to a stream */
if (decl_changed)
goto end;
flags = 0;
/* However, it is perfectly fine to change the declaration every now and then. We don't want a game that
goto end;
start = 0;
case CONV_NONE:
case CONV_FLOAT16_2:
ENTER_GL();
GL_EXTCALL(glBufferSubDataARB(This->buffer_type_hint, 0, vertices * This->conversion_stride, data));
LEAVE_GL();
case CONV_NONE:
case CONV_D3DCOLOR:
case CONV_POSITIONT:
case CONV_FLOAT16_2:
ENTER_GL();
LEAVE_GL();
end:
else if((flags & (WINED3DLOCK_DISCARD | WINED3DLOCK_NOOVERWRITE)) == (WINED3DLOCK_DISCARD | WINED3DLOCK_NOOVERWRITE))
else if (flags & (WINED3DLOCK_DISCARD | WINED3DLOCK_NOOVERWRITE) && !(buffer->resource.usage & WINED3DUSAGE_DYNAMIC))
return flags;
return ret;
static HRESULT STDMETHODCALLTYPE buffer_Map(IWineD3DBuffer *iface, UINT offset, UINT size, BYTE **data, DWORD flags)
ENTER_GL();
LEAVE_GL();
ENTER_GL();
This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(This->buffer_type_hint, GL_READ_WRITE_ARB));
LEAVE_GL();
ENTER_GL();
LEAVE_GL();
if (dirty)
TRACE("Returning memory at %p (base %p, offset %u)\n", *data, This->resource.allocatedMemory, offset);
return WINED3D_OK;
ULONG i;
return WINED3D_OK;
return WINED3D_OK;
ENTER_GL();
LEAVE_GL();
return WINED3D_OK;
return WINED3D_OK;
#ifdef VBOX_WITH_WDDM
const struct wined3d_format_desc *format_desc = getFormatDescEntry(format, &device->adapter->gl_info);
if (!size)
return WINED3DERR_INVALIDCALL;
#ifdef VBOX_WITH_WDDM
return hr;
TRACE("size %#x, usage %#x, format %s, memory @ %p, iface @ %p.\n", buffer->resource.size, buffer->resource.usage,
dynamic_buffer_ok = gl_info->supported[APPLE_FLUSH_BUFFER_RANGE] || gl_info->supported[ARB_MAP_BUFFER_RANGE];
if (data)
return hr;
return hr;
return E_OUTOFMEMORY;
return WINED3D_OK;