コード例 #1
0
void ShaderVariation::Release()
{
    if (object_.ptr_ && graphics_)
    {
        graphics_->CleanupShaderPrograms(this);

        if (type_ == VS)
        {
            if (graphics_->GetVertexShader() == this)
                graphics_->SetShaders(0, 0);
        }
        else
        {
            if (graphics_->GetPixelShader() == this)
                graphics_->SetShaders(0, 0);
        }
    }

    ATOMIC_SAFE_RELEASE(object_.ptr_);

    compilerOutput_.Clear();

    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
        useTextureUnit_[i] = false;
    parameters_.Clear();
}
コード例 #2
0
bool IndexBuffer::Create()
{
    Release();

    if (!indexCount_)
        return true;

    if (graphics_)
    {
        D3D11_BUFFER_DESC bufferDesc;
        memset(&bufferDesc, 0, sizeof bufferDesc);
        bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
        bufferDesc.CPUAccessFlags = dynamic_ ? D3D11_CPU_ACCESS_WRITE : 0;
        bufferDesc.Usage = dynamic_ ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
        bufferDesc.ByteWidth = (UINT)(indexCount_ * indexSize_);

        HRESULT hr = graphics_->GetImpl()->GetDevice()->CreateBuffer(&bufferDesc, 0, (ID3D11Buffer**)&object_.ptr_);
        if (FAILED(hr))
        {
            ATOMIC_SAFE_RELEASE(object_.ptr_);
            ATOMIC_LOGD3DERROR("Failed to create index buffer", hr);
            return false;
        }
    }

    return true;
}
コード例 #3
0
void IndexBuffer::Release()
{
    Unlock();

    if (graphics_ && graphics_->GetIndexBuffer() == this)
        graphics_->SetIndexBuffer(0);

    ATOMIC_SAFE_RELEASE(object_.ptr_);
}
コード例 #4
0
void VertexBuffer::Release()
{
    Unlock();

    if (graphics_)
    {
        for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
        {
            if (graphics_->GetVertexBuffer(i) == this)
                graphics_->SetVertexBuffer(0);
        }
    }

    ATOMIC_SAFE_RELEASE(object_.ptr_);
}
コード例 #5
0
bool VertexBuffer::Create()
{
    Release();

    if (!vertexCount_ || elements_.Empty())
        return true;

    if (graphics_)
    {
        if (graphics_->IsDeviceLost())
        {
            ATOMIC_LOGWARNING("Vertex buffer creation while device is lost");
            return true;
        }

        unsigned pool = dynamic_ ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
        unsigned d3dUsage = dynamic_ ? D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY : 0;

        IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
        HRESULT hr = device->CreateVertexBuffer(
            vertexCount_ * vertexSize_,
            d3dUsage,
            0,
            (D3DPOOL)pool,
            (IDirect3DVertexBuffer9**)&object_.ptr_,
            0);
        if (FAILED(hr))
        {
            ATOMIC_SAFE_RELEASE(object_.ptr_);
            ATOMIC_LOGD3DERROR("Could not create vertex buffer", hr);
            return false;
        }
    }

    return true;
}
コード例 #6
0
bool IndexBuffer::Create()
{
    Release();

    if (!indexCount_)
        return true;

    if (graphics_)
    {
        if (graphics_->IsDeviceLost())
        {
            ATOMIC_LOGWARNING("Index buffer creation while device is lost");
            return true;
        }

        unsigned pool = dynamic_ ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
        unsigned d3dUsage = dynamic_ ? D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY : 0;

        IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
        HRESULT hr = device->CreateIndexBuffer(
            indexCount_ * indexSize_,
            d3dUsage,
            indexSize_ == sizeof(unsigned) ? D3DFMT_INDEX32 : D3DFMT_INDEX16,
            (D3DPOOL)pool,
            (IDirect3DIndexBuffer9**)&object_,
            0);
        if (FAILED(hr))
        {
            ATOMIC_SAFE_RELEASE(object_.ptr_)
            ATOMIC_LOGD3DERROR("Could not create index buffer", hr);
            return false;
        }
    }

    return true;
}
コード例 #7
0
bool ShaderVariation::Create()
{
    Release();

    if (!graphics_)
        return false;

    if (!owner_)
    {
        compilerOutput_ = "Owner shader has expired";
        return false;
    }

    // Check for up-to-date bytecode on disk
    String path, name, extension;
    SplitPath(owner_->GetName(), path, name, extension);
    extension = type_ == VS ? ".vs3" : ".ps3";

    String binaryShaderName = graphics_->GetShaderCacheDir() + name + "_" + StringHash(defines_).ToString() + extension;

    if (!LoadByteCode(binaryShaderName))
    {
        // Compile shader if don't have valid bytecode
        if (!Compile())
            return false;
        // Save the bytecode after successful compile, but not if the source is from a package
        if (owner_->GetTimeStamp())
            SaveByteCode(binaryShaderName);
    }

    // Then create shader from the bytecode
    IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
    if (type_ == VS)
    {
        HRESULT hr = device->CreateVertexShader(
            (const DWORD*)&byteCode_[0],
            (IDirect3DVertexShader9**)&object_.ptr_);
        if (FAILED(hr))
        {
            ATOMIC_SAFE_RELEASE(object_.ptr_);
            compilerOutput_ = "Could not create vertex shader (HRESULT " + ToStringHex((unsigned)hr) + ")";
        }
    }
    else
    {
        HRESULT hr = device->CreatePixelShader(
            (const DWORD*)&byteCode_[0],
            (IDirect3DPixelShader9**)&object_.ptr_);
        if (FAILED(hr))
        {
            ATOMIC_SAFE_RELEASE(object_.ptr_);
            compilerOutput_ = "Could not create pixel shader (HRESULT " + ToStringHex((unsigned)hr) + ")";
        }
    }

    // The bytecode is not needed on Direct3D9 after creation, so delete it to save memory
    byteCode_.Clear();
    byteCode_.Reserve(0);

    return object_.ptr_ != 0;
}
コード例 #8
0
bool ShaderVariation::Compile()
{
    const String& sourceCode = owner_->GetSourceCode(type_);
    Vector<String> defines = defines_.Split(' ');

    // Set the entrypoint, profile and flags according to the shader being compiled
    const char* entryPoint = 0;
    const char* profile = 0;
    unsigned flags = D3DCOMPILE_OPTIMIZATION_LEVEL3;

    if (type_ == VS)
    {
        entryPoint = "VS";
        defines.Push("COMPILEVS");
        profile = "vs_3_0";
    }
    else
    {
        entryPoint = "PS";
        defines.Push("COMPILEPS");
        profile = "ps_3_0";
        flags |= D3DCOMPILE_PREFER_FLOW_CONTROL;
    }

    defines.Push("MAXBONES=" + String(Graphics::GetMaxBones()));

    // Collect defines into macros
    Vector<String> defineValues;
    PODVector<D3D_SHADER_MACRO> macros;

    for (unsigned i = 0; i < defines.Size(); ++i)
    {
        unsigned equalsPos = defines[i].Find('=');
        if (equalsPos != String::NPOS)
        {
            defineValues.Push(defines[i].Substring(equalsPos + 1));
            defines[i].Resize(equalsPos);
        }
        else
            defineValues.Push("1");
    }
    for (unsigned i = 0; i < defines.Size(); ++i)
    {
        D3D_SHADER_MACRO macro;
        macro.Name = defines[i].CString();
        macro.Definition = defineValues[i].CString();
        macros.Push(macro);

        // In debug mode, check that all defines are referenced by the shader code
#ifdef _DEBUG
        if (sourceCode.Find(defines[i]) == String::NPOS)
            ATOMIC_LOGWARNING("Shader " + GetFullName() + " does not use the define " + defines[i]);
#endif
    }

    D3D_SHADER_MACRO endMacro;
    endMacro.Name = 0;
    endMacro.Definition = 0;
    macros.Push(endMacro);

    // Compile using D3DCompile
    ID3DBlob* shaderCode = 0;
    ID3DBlob* errorMsgs = 0;

    HRESULT hr = D3DCompile(sourceCode.CString(), sourceCode.Length(), owner_->GetName().CString(), &macros.Front(), 0,
        entryPoint, profile, flags, 0, &shaderCode, &errorMsgs);
    if (FAILED(hr))
    {
        // Do not include end zero unnecessarily
        compilerOutput_ = String((const char*)errorMsgs->GetBufferPointer(), (unsigned)errorMsgs->GetBufferSize() - 1);
    }
    else
    {
        if (type_ == VS)
            ATOMIC_LOGDEBUG("Compiled vertex shader " + GetFullName());
        else
            ATOMIC_LOGDEBUG("Compiled pixel shader " + GetFullName());

        // Inspect the produced bytecode using MojoShader, then strip and store it
        unsigned char* bufData = (unsigned char*)shaderCode->GetBufferPointer();
        unsigned bufSize = (unsigned)shaderCode->GetBufferSize();
        ParseParameters(bufData, bufSize);
        CopyStrippedCode(byteCode_, bufData, bufSize);
    }

    ATOMIC_SAFE_RELEASE(shaderCode);
    ATOMIC_SAFE_RELEASE(errorMsgs);

    return !byteCode_.Empty();
}
コード例 #9
0
VertexDeclaration::VertexDeclaration(Graphics* graphics, ShaderVariation* vertexShader, VertexBuffer** vertexBuffers) :
    inputLayout_(0)
{
    PODVector<D3D11_INPUT_ELEMENT_DESC> elementDescs;
    unsigned prevBufferDescs = 0;

    for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
    {
        if (!vertexBuffers[i])
            continue;

        const PODVector<VertexElement>& srcElements = vertexBuffers[i]->GetElements();
        bool isExisting = false;

        for (unsigned j = 0; j < srcElements.Size(); ++j)
        {
            const VertexElement& srcElement = srcElements[j];
            const char* semanticName = ShaderVariation::elementSemanticNames[srcElement.semantic_];

            // Override existing element if necessary
            for (unsigned k = 0; k < prevBufferDescs; ++k)
            {
                if (elementDescs[k].SemanticName == semanticName && elementDescs[k].SemanticIndex == srcElement.index_)
                {
                    isExisting = true;
                    elementDescs[k].InputSlot = i;
                    elementDescs[k].AlignedByteOffset = srcElement.offset_;
                    elementDescs[k].InputSlotClass = srcElement.perInstance_ ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
                    elementDescs[k].InstanceDataStepRate = srcElement.perInstance_ ? 1 : 0;
                    break;
                }
            }

            if (isExisting)
                continue;

            D3D11_INPUT_ELEMENT_DESC newDesc;
            newDesc.SemanticName = semanticName;
            newDesc.SemanticIndex = srcElement.index_;
            newDesc.Format = d3dElementFormats[srcElement.type_];
            newDesc.InputSlot = (UINT)i;
            newDesc.AlignedByteOffset = srcElement.offset_;
            newDesc.InputSlotClass = srcElement.perInstance_ ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
            newDesc.InstanceDataStepRate = srcElement.perInstance_ ? 1 : 0;
            elementDescs.Push(newDesc);
        }

        prevBufferDescs = elementDescs.Size();
    }

    if (elementDescs.Empty())
        return;

    const PODVector<unsigned char>& byteCode = vertexShader->GetByteCode();

    HRESULT hr = graphics->GetImpl()->GetDevice()->CreateInputLayout(&elementDescs[0], (UINT)elementDescs.Size(), &byteCode[0],
        byteCode.Size(), (ID3D11InputLayout**)&inputLayout_);
    if (FAILED(hr))
    {
        ATOMIC_SAFE_RELEASE(inputLayout_);
        ATOMIC_LOGERRORF("Failed to create input layout for shader %s due to missing vertex element(s) (HRESULT %x)",
            vertexShader->GetFullName().CString(), (unsigned)hr);
    }
}
コード例 #10
0
VertexDeclaration::~VertexDeclaration()
{
    ATOMIC_SAFE_RELEASE(inputLayout_);
}
コード例 #11
0
bool Texture2D::Create()
{
    Release();

    if (!graphics_ || !width_ || !height_)
        return false;

    if (graphics_->IsDeviceLost())
    {
        ATOMIC_LOGWARNING("Texture creation while device is lost");
        return true;
    }

    unsigned pool = usage_ > TEXTURE_STATIC ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
    unsigned d3dUsage = 0;

    switch (usage_)
    {
    case TEXTURE_DYNAMIC:
        d3dUsage |= D3DUSAGE_DYNAMIC;
        break;
    case TEXTURE_RENDERTARGET:
        d3dUsage |= D3DUSAGE_RENDERTARGET;
        break;
    case TEXTURE_DEPTHSTENCIL:
        d3dUsage |= D3DUSAGE_DEPTHSTENCIL;
        break;
    default:
        break;
    }

    IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
    // If creating a depth-stencil texture, and it is not supported, create a depth-stencil surface instead
    if (usage_ == TEXTURE_DEPTHSTENCIL && !graphics_->GetImpl()->CheckFormatSupport((D3DFORMAT)format_, d3dUsage, D3DRTYPE_TEXTURE))
    {
        HRESULT hr = device->CreateDepthStencilSurface(
            (UINT)width_,
            (UINT)height_,
            (D3DFORMAT)format_,
            D3DMULTISAMPLE_NONE,
            0,
            FALSE,
            (IDirect3DSurface9**)&renderSurface_->surface_,
            0);
        if (FAILED(hr))
        {
            ATOMIC_SAFE_RELEASE(renderSurface_->surface_);
            ATOMIC_LOGD3DERROR("Could not create depth-stencil surface", hr);
            return false;
        }

        levels_ = 1;
    }
    else
    {
        HRESULT hr = graphics_->GetImpl()->GetDevice()->CreateTexture(
            (UINT)width_,
            (UINT)height_,
            requestedLevels_,
            d3dUsage,
            (D3DFORMAT)format_,
            (D3DPOOL)pool,
            (IDirect3DTexture9**)&object_,
            0);
        if (FAILED(hr))
        {
            ATOMIC_SAFE_RELEASE(object_.ptr_);
            ATOMIC_LOGD3DERROR("Could not create texture", hr);
            return false;
        }

        levels_ = ((IDirect3DTexture9*)object_.ptr_)->GetLevelCount();

        if (usage_ >= TEXTURE_RENDERTARGET)
        {
            hr = ((IDirect3DTexture9*)object_.ptr_)->GetSurfaceLevel(0, (IDirect3DSurface9**)&renderSurface_->surface_);
            if (FAILED(hr))
                ATOMIC_LOGD3DERROR("Could not get rendertarget surface", hr);
        }
    }

    return true;
}
コード例 #12
0
bool Texture2D::GetData(unsigned level, void* dest) const
{
    if (!object_.ptr_)
    {
        ATOMIC_LOGERROR("No texture created, can not get data");
        return false;
    }

    if (!dest)
    {
        ATOMIC_LOGERROR("Null destination for getting data");
        return false;
    }

    if (level >= levels_)
    {
        ATOMIC_LOGERROR("Illegal mip level for getting data");
        return false;
    }

    if (graphics_->IsDeviceLost())
    {
        ATOMIC_LOGWARNING("Getting texture data while device is lost");
        return false;
    }

    int levelWidth = GetLevelWidth(level);
    int levelHeight = GetLevelHeight(level);

    D3DLOCKED_RECT d3dLockedRect;
    RECT d3dRect;
    d3dRect.left = 0;
    d3dRect.top = 0;
    d3dRect.right = levelWidth;
    d3dRect.bottom = levelHeight;

    IDirect3DSurface9* offscreenSurface = 0;
    // Need to use a offscreen surface & GetRenderTargetData() for rendertargets
    if (renderSurface_)
    {
        if (level != 0)
        {
            ATOMIC_LOGERROR("Can only get mip level 0 data from a rendertarget");
            return false;
        }

        IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
        HRESULT hr = device->CreateOffscreenPlainSurface((UINT)width_, (UINT)height_, (D3DFORMAT)format_,
            D3DPOOL_SYSTEMMEM, &offscreenSurface, 0);
        if (FAILED(hr))
        {
            ATOMIC_SAFE_RELEASE(offscreenSurface);
            ATOMIC_LOGD3DERROR("Could not create surface for getting rendertarget data", hr);
            return false;
        }
        hr = device->GetRenderTargetData((IDirect3DSurface9*)renderSurface_->GetSurface(), offscreenSurface);
        if (FAILED(hr))
        {
            ATOMIC_LOGD3DERROR("Could not get rendertarget data", hr);
            offscreenSurface->Release();
            return false;
        }
        hr = offscreenSurface->LockRect(&d3dLockedRect, &d3dRect, D3DLOCK_READONLY);
        if (FAILED(hr))
        {
            ATOMIC_LOGD3DERROR("Could not lock surface for getting rendertarget data", hr);
            offscreenSurface->Release();
            return false;
        }
    }
    else
    {
        HRESULT hr = ((IDirect3DTexture9*)object_.ptr_)->LockRect(level, &d3dLockedRect, &d3dRect, D3DLOCK_READONLY);
        if (FAILED(hr))
        {
            ATOMIC_LOGD3DERROR("Could not lock texture", hr);
            return false;
        }
    }

    int height = levelHeight;
    if (IsCompressed())
        height = (height + 3) >> 2;

    unsigned char* destPtr = (unsigned char*)dest;
    unsigned rowSize = GetRowDataSize(levelWidth);
    // GetRowDataSize() returns CPU-side (destination) data size, so need to convert for X8R8G8B8
    if (format_ == D3DFMT_X8R8G8B8)
        rowSize = rowSize / 3 * 4;

    // Perform conversion to RGB / RGBA as necessary
    switch (format_)
    {
    default:
        for (int i = 0; i < height; ++i)
        {
            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
            memcpy(destPtr, src, rowSize);
            destPtr += rowSize;
        }
        break;

    case D3DFMT_X8R8G8B8:
        for (int i = 0; i < height; ++i)
        {
            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
            for (int j = 0; j < levelWidth; ++j)
            {
                destPtr[2] = *src++;
                destPtr[1] = *src++;
                destPtr[0] = *src++;
                ++src;
                destPtr += 3;
            }
        }
        break;

    case D3DFMT_A8R8G8B8:
        for (int i = 0; i < height; ++i)
        {
            unsigned char* src = (unsigned char*)d3dLockedRect.pBits + i * d3dLockedRect.Pitch;
            for (int j = 0; j < levelWidth; ++j)
            {
                destPtr[2] = *src++;
                destPtr[1] = *src++;
                destPtr[0] = *src++;
                destPtr[3] = *src++;
                destPtr += 4;
            }
        }
        break;
    }

    if (offscreenSurface)
    {
        offscreenSurface->UnlockRect();
        offscreenSurface->Release();
    }
    else
        ((IDirect3DTexture9*)object_.ptr_)->UnlockRect(level);

    return true;
}