Exemple #1
0
std::size_t VertexDataManager::writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute, GLsizei instances)
{
    Buffer *buffer = attribute.mBoundBuffer.get();

    int inputStride = attribute.stride();
    int elementSize = attribute.typeSize();
    const FormatConverter &converter = formatConverter(attribute);
    std::size_t streamOffset = 0;

    void *output = NULL;
    
    if (vertexBuffer)
    {
        output = vertexBuffer->map(attribute, spaceRequired(attribute, count, instances), &streamOffset);
    }

    if (output == NULL)
    {
        ERR("Failed to map vertex buffer.");
        return -1;
    }

    const char *input = NULL;

    if (buffer)
    {
        int offset = attribute.mOffset;

        input = static_cast<const char*>(buffer->data()) + offset;
    }
    else
    {
        input = static_cast<const char*>(attribute.mPointer);
    }

    if (instances == 0 || attribute.mDivisor == 0)
    {
        input += inputStride * start;
    }

    if (converter.identity && inputStride == elementSize)
    {
        memcpy(output, input, count * inputStride);
    }
    else
    {
        converter.convertArray(input, inputStride, count, output);
    }

    vertexBuffer->unmap();

    return streamOffset;
}
gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData &currentValue,
                                               GLint start, GLsizei count, GLsizei instances, unsigned int offset)
{
    if (!mVertexBuffer)
    {
        return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized.");
    }

    gl::Buffer *buffer = attrib.buffer.get();

    int inputStride = gl::ComputeVertexAttributeStride(attrib);
    int elementSize = gl::ComputeVertexAttributeTypeSize(attrib);

    DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0;

    uint8_t *mapPtr = NULL;

    unsigned int mapSize;
    gl::Error error = spaceRequired(attrib, count, instances, &mapSize);
    if (error.isError())
    {
        return error;
    }

    HRESULT result = mVertexBuffer->Lock(offset, mapSize, reinterpret_cast<void**>(&mapPtr), lockFlags);
    if (FAILED(result))
    {
        return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal vertex buffer, HRESULT: 0x%08x.", result);
    }

    const uint8_t *input = NULL;
    if (attrib.enabled)
    {
        if (buffer)
        {
            BufferD3D *storage = BufferD3D::makeFromBuffer(buffer);
            ASSERT(storage);
            gl::Error error = storage->getData(&input);
            if (error.isError())
            {
                return error;
            }
            input += static_cast<int>(attrib.offset);
        }
        else
        {
            input = static_cast<const uint8_t*>(attrib.pointer);
        }
    }
    else
    {
        input = reinterpret_cast<const uint8_t*>(currentValue.FloatValues);
    }

    if (instances == 0 || attrib.divisor == 0)
    {
        input += inputStride * start;
    }

    gl::VertexFormat vertexFormat(attrib, currentValue.Type);
    const d3d9::VertexFormat &d3dVertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat);
    bool needsConversion = (d3dVertexInfo.conversionType & VERTEX_CONVERT_CPU) > 0;

    if (!needsConversion && inputStride == elementSize)
    {
        size_t copySize = static_cast<size_t>(count) * static_cast<size_t>(inputStride);
        memcpy(mapPtr, input, copySize);
    }
    else
    {
        d3dVertexInfo.copyFunction(input, inputStride, count, mapPtr);
    }

    mVertexBuffer->Unlock();

    return gl::Error(GL_NO_ERROR);
}
Exemple #3
0
GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances)
{
    if (!mStreamingBuffer)
    {
        return GL_OUT_OF_MEMORY;
    }

    const VertexAttributeArray &attribs = mContext->getVertexAttributes();
    Program *program = mContext->getCurrentProgram();
    ProgramBinary *programBinary = program->getProgramBinary();

    for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
    {
        translated[attributeIndex].active = (programBinary->getSemanticIndex(attributeIndex) != -1);
    }

    // Determine the required storage size per used buffer, and invalidate static buffers that don't contain matching attributes
    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (translated[i].active && attribs[i].mArrayEnabled)
        {
            Buffer *buffer = attribs[i].mBoundBuffer.get();
            StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;

            if (staticBuffer)
            {
                if (staticBuffer->size() == 0)
                {
                    int totalCount = elementsInBuffer(attribs[i], buffer->size());
                    staticBuffer->addRequiredSpace(spaceRequired(attribs[i], totalCount, 0));
                }
                else if (staticBuffer->lookupAttribute(attribs[i]) == -1)
                {
                    // This static buffer doesn't have matching attributes, so fall back to using the streaming buffer
                    // Add the space of all previous attributes belonging to the invalidated static buffer to the streaming buffer
                    for (int previous = 0; previous < i; previous++)
                    {
                        if (translated[previous].active && attribs[previous].mArrayEnabled)
                        {
                            Buffer *previousBuffer = attribs[previous].mBoundBuffer.get();
                            StaticVertexBuffer *previousStaticBuffer = previousBuffer ? previousBuffer->getStaticVertexBuffer() : NULL;

                            if (staticBuffer == previousStaticBuffer)
                            {
                                mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[previous], count, instances));
                            }
                        }
                    }

                    mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count, instances));

                    buffer->invalidateStaticData();
                }    
            }
            else
            {
                mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count, instances));
            }
        }
    }

    // Reserve the required space per used buffer
    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (translated[i].active && attribs[i].mArrayEnabled)
        {
            Buffer *buffer = attribs[i].mBoundBuffer.get();
            ArrayVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
            ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : mStreamingBuffer;

            if (vertexBuffer)
            {
                vertexBuffer->reserveRequiredSpace();
            }
        }
    }

    // Perform the vertex data translations
    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (translated[i].active)
        {
            if (attribs[i].mArrayEnabled)
            {
                Buffer *buffer = attribs[i].mBoundBuffer.get();

                if (!buffer && attribs[i].mPointer == NULL)
                {
                    // This is an application error that would normally result in a crash, but we catch it and return an error
                    ERR("An enabled vertex array has no buffer and no pointer.");
                    return GL_INVALID_OPERATION;
                }

                const FormatConverter &converter = formatConverter(attribs[i]);

                StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
                ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : static_cast<ArrayVertexBuffer*>(mStreamingBuffer);

                std::size_t streamOffset = -1;

                if (staticBuffer)
                {
                    streamOffset = staticBuffer->lookupAttribute(attribs[i]);

                    if (streamOffset == -1)
                    {
                        // Convert the entire buffer
                        int totalCount = elementsInBuffer(attribs[i], buffer->size());
                        int startIndex = attribs[i].mOffset / attribs[i].stride();

                        streamOffset = writeAttributeData(staticBuffer, -startIndex, totalCount, attribs[i], 0);
                    }

                    if (streamOffset != -1)
                    {
                        streamOffset += (attribs[i].mOffset / attribs[i].stride()) * converter.outputElementSize;

                        if (instances == 0 || attribs[i].mDivisor == 0)
                        {
                            streamOffset += start * converter.outputElementSize;
                        }
                    }
                }
                else
                {
                    streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i], instances);
                }

                if (streamOffset == -1)
                {
                    return GL_OUT_OF_MEMORY;
                }

                translated[i].vertexBuffer = vertexBuffer->getBuffer();
                translated[i].serial = vertexBuffer->getSerial();
                translated[i].divisor = attribs[i].mDivisor;

                translated[i].type = converter.d3dDeclType;
                translated[i].stride = converter.outputElementSize;
                translated[i].offset = streamOffset;
            }
            else
            {
                if (!mCurrentValueBuffer[i])
                {
                    mCurrentValueBuffer[i] = new StreamingVertexBuffer(mDevice, CONSTANT_VERTEX_BUFFER_SIZE);
                }

                StreamingVertexBuffer *buffer = mCurrentValueBuffer[i];

                if (mDirtyCurrentValue[i])
                {
                    const int requiredSpace = 4 * sizeof(float);
                    buffer->addRequiredSpace(requiredSpace);
                    buffer->reserveRequiredSpace();
                    float *data = static_cast<float*>(buffer->map(VertexAttribute(), requiredSpace, &mCurrentValueOffsets[i]));
                    if (data)
                    {
                        data[0] = attribs[i].mCurrentValue[0];
                        data[1] = attribs[i].mCurrentValue[1];
                        data[2] = attribs[i].mCurrentValue[2];
                        data[3] = attribs[i].mCurrentValue[3];
                        buffer->unmap();
                        mDirtyCurrentValue[i] = false;
                    }
                }

                translated[i].vertexBuffer = mCurrentValueBuffer[i]->getBuffer();
                translated[i].serial = mCurrentValueBuffer[i]->getSerial();
                translated[i].divisor = 0;

                translated[i].type = D3DDECLTYPE_FLOAT4;
                translated[i].stride = 0;
                translated[i].offset = mCurrentValueOffsets[i];
            }
        }
    }

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (translated[i].active && attribs[i].mArrayEnabled)
        {
            Buffer *buffer = attribs[i].mBoundBuffer.get();

            if (buffer)
            {
                buffer->promoteStaticUsage(count * attribs[i].typeSize());
            }
        }
    }

    return GL_NO_ERROR;
}
gl::Error VertexBuffer9::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances,
                                          unsigned int *outSpaceRequired) const
{
    return spaceRequired(attrib, count, instances, outSpaceRequired);
}