//----------------------------------------------------------------------------------------------------------------------------------
void RosUmdAdapter::Open( D3D10DDIARG_OPENADAPTER* pArgs )
{

    m_hRTAdapter = pArgs->hRTAdapter;
    m_Interface = pArgs->Interface;
    m_Version = pArgs->Version;
    m_pMSCallbacks = pArgs->pAdapterCallbacks;

    D3DDDICB_QUERYADAPTERINFO   queryAdapterInfo = { 0 };
    HRESULT hr;

    queryAdapterInfo.pPrivateDriverData = &m_rosAdapterInfo;
    queryAdapterInfo.PrivateDriverDataSize = sizeof(m_rosAdapterInfo);

    hr = m_pMSCallbacks->pfnQueryAdapterInfoCb(
        m_hRTAdapter.handle,
        &queryAdapterInfo);
    if (FAILED(hr))
    {
        throw RosUmdException(hr);
    }

    const D3D10_2DDI_ADAPTERFUNCS AdapterFuncs =
    {
        CalcPrivateDeviceSize,
        CreateDevice,
        CloseAdapter,
        GetSupportedVersions,
        GetCaps,
    };

    *pArgs->pAdapterFuncs_2 = AdapterFuncs;

    pArgs->hAdapter = CastTo();
}
_Use_decl_annotations_
void RosUmdResource::CopyTFormatToLinear (
    const void* Source,
    UINT SourceWidthTiles,  // width in 4k tiles
    UINT SourceHeightTiles, // height in 4k tiles
    void* Dest,
    UINT DestPitch,
    UINT DestHeight
    )
{
    if (DestPitch % VC4_MICRO_TILE_WIDTH_BYTES) {
        ROS_LOG_ERROR(
            "Destination pitch is not aligned to microtile width. "
            "(DestPitch = %d, VC4_MICRO_TILE_WIDTH_BYTES = %d)",
            DestPitch,
            VC4_MICRO_TILE_WIDTH_BYTES);
        throw RosUmdException(E_INVALIDARG);
    }

    const BYTE* const destEnd = static_cast<BYTE*>(Dest) + (DestPitch * DestHeight);
    const BYTE* const srcEnd = static_cast<const BYTE*>(Source) +
        (SourceWidthTiles * SourceHeightTiles * VC4_4KB_TILE_SIZE_BYTES);

    // build destination image in scanline order
    for (UINT y = 0; y < DestHeight; ++y) {
        const UINT offsetWithinMicrotile =
            (y % VC4_MICRO_TILE_HEIGHT) * VC4_MICRO_TILE_WIDTH_BYTES;

        // destRow points to beginning of row y
        BYTE* const destRow = static_cast<BYTE*>(Dest) + y * DestPitch;

        for (UINT x = 0; x < DestPitch; x += VC4_MICRO_TILE_WIDTH_BYTES) {
            TileCoord tileCoord(
                x / VC4_MICRO_TILE_WIDTH_BYTES,
                y / VC4_MICRO_TILE_HEIGHT,
                SourceWidthTiles);

            // Compute the start of the line within the micro tile
            const BYTE* src =
                static_cast<const BYTE*>(Source) +
                tileCoord.ByteOffset() +
                offsetWithinMicrotile;
            NT_ASSERT((src + VC4_MICRO_TILE_WIDTH_BYTES) <= srcEnd);
            UNREFERENCED_PARAMETER(srcEnd);

            BYTE* dest = destRow + x;
            NT_ASSERT((dest + VC4_MICRO_TILE_WIDTH_BYTES) <= destEnd);
            UNREFERENCED_PARAMETER(destEnd);

            memcpy(dest, src, VC4_MICRO_TILE_WIDTH_BYTES);
        }
    }
}
void
RosUmdResource::CalculateMemoryLayout(
    void)
{
    switch (m_resourceDimension)
    {
    case D3D10DDIRESOURCE_BUFFER:
        {
            m_hwLayout = RosHwLayout::Linear;

            // TODO(bhouse) Need mapping code from resource DXGI format to hw format
            m_hwWidthPixels = m_mip0Info.TexelWidth;
            m_hwHeightPixels = m_mip0Info.TexelHeight;

            m_hwSizeBytes = m_mip0Info.TexelWidth * CPixel::BytesPerPixel(m_format);
            NT_ASSERT(this->Pitch() == m_hwSizeBytes);
        }
    break;
    case D3D10DDIRESOURCE_TEXTURE2D:
        {
            // get layout and alignment requirement from binding and format
            const auto reqs =
                Get2dTextureLayoutRequirements(m_bindFlags, m_format);

            const UINT unalignedPitch =
                m_mip0Info.TexelWidth * CPixel::BytesPerPixel(m_format);
            const UINT alignedPitch = 
                AlignValue(unalignedPitch, reqs.PitchAlign);

            const UINT unalignedHeight = m_mip0Info.TexelHeight;
            const UINT alignedHeight =
                AlignValue(unalignedHeight, reqs.HeightAlign);

            m_hwLayout = reqs.Layout;
            m_hwWidthPixels = alignedPitch / CPixel::BytesPerPixel(m_format);
            m_hwHeightPixels = alignedHeight;
            m_hwSizeBytes = alignedPitch * alignedHeight;
        }
        break;
    case D3D10DDIRESOURCE_TEXTURE1D:
    case D3D10DDIRESOURCE_TEXTURE3D:
    case D3D10DDIRESOURCE_TEXTURECUBE:
    default:
        throw RosUmdException(DXGI_DDI_ERR_UNSUPPORTED);
    }
}
RosUmdResource::_LayoutRequirements RosUmdResource::Get2dTextureLayoutRequirements (
    UINT BindFlags,
    DXGI_FORMAT Format
    )
{
    RosHwLayout hwLayout;
    UINT pitchAlign, heightAlign;

    switch (BindFlags)
    {
    case 0:
        // non-bindable resources (e.g. staging resources) must be pitch-aligned
        // to microtile width so that we can copy efficiently between T-format
        // and linear resources
        hwLayout = RosHwLayout::Linear;
        pitchAlign = VC4_MICRO_TILE_WIDTH_BYTES;
        heightAlign = 1;
        break;

    case D3D10_DDI_BIND_RENDER_TARGET:
    case D3D10_DDI_BIND_RENDER_TARGET | D3D10_DDI_BIND_SHADER_RESOURCE:
        // non-displayable render targets use T-Format, and must be aligned
        // to the binning tile size
        hwLayout = RosHwLayout::Tiled;
        pitchAlign = VC4_BINNING_TILE_PIXELS * CPixel::BytesPerPixel(Format);
        heightAlign = VC4_BINNING_TILE_PIXELS;
        break;

    //case D3D10_DDI_BIND_RENDER_TARGET:
    case D3D10_DDI_BIND_RENDER_TARGET | D3D10_DDI_BIND_PRESENT:
    case D3D10_DDI_BIND_RENDER_TARGET | D3D10_DDI_BIND_SHADER_RESOURCE | D3D10_DDI_BIND_PRESENT:
        // displayable render target uses linear (raster) format, and must be
        // aligned to binning tile size
        hwLayout = RosHwLayout::Linear;
        pitchAlign = VC4_BINNING_TILE_PIXELS * CPixel::BytesPerPixel(Format);
        heightAlign = VC4_BINNING_TILE_PIXELS;
        break;

    case D3D10_DDI_BIND_SHADER_RESOURCE:
    case D3D10_DDI_BIND_DEPTH_STENCIL:
        // bindable textures and depth stencils use T-Format and must be
        // aligned to the t-format tile size
        // XXX: Disable tiled format until issue #48 is fixed.
        hwLayout = RosHwLayout::Linear; // RosHwLayout::Tiled;
        pitchAlign = VC4_4KB_TILE_WIDTH_BYTES;
        heightAlign = VC4_4KB_TILE_HEIGHT;
        break;

    case D3D10_DDI_BIND_PRESENT:
        // display-only surfaces use linear format with no alignment requirement
        hwLayout = RosHwLayout::Linear;
        pitchAlign = CPixel::BytesPerPixel(Format);
        heightAlign = 1;
        break;

    case D3D10_DDI_BIND_VERTEX_BUFFER:
    case D3D10_DDI_BIND_INDEX_BUFFER:
    case D3D10_DDI_BIND_CONSTANT_BUFFER:
        ROS_LOG_ERROR(
            "Unsupported bind flag for 2D texture. (BindFlags = 0x%x)",
            BindFlags);
        throw RosUmdException(E_INVALIDARG);
    case D3D10_DDI_BIND_STREAM_OUTPUT:
    default:
        ROS_LOG_ERROR("Unsupported or invalid bind flags: 0x%x", BindFlags);
        throw RosUmdException(E_INVALIDARG);
    }

    return _LayoutRequirements{hwLayout, pitchAlign, heightAlign};
}
void
RosUmdPipelineShader::Update()
{
    // TODO: state dirtiness check.
    if (m_pCompiler)
    {
        return;
    }

    assert(m_pCode != NULL);

    const UINT *ShaderLinkage[2] = { NULL, NULL }; // Downstream, Upstream.

    switch (m_ProgramType)
    {
    case D3D10_SB_VERTEX_SHADER:
        assert(m_pDevice->m_pixelShader);
        ShaderLinkage[0] = m_pDevice->m_pixelShader->GetHLSLCode();
        break;
    case D3D10_SB_PIXEL_SHADER:
        assert(m_pDevice->m_vertexShader);
        ShaderLinkage[1] = m_pDevice->m_vertexShader->GetHLSLCode();
        break;
    default:
        assert(false);
    };

    m_pCompiler = RosCompilerCreate(m_ProgramType,
                                    m_pCode,
                                    ShaderLinkage[0], // Downstream
                                    ShaderLinkage[1], // Upstream
                                    m_pDevice->m_blendState->GetDesc(),
                                    m_pDevice->m_depthStencilState->GetDesc(),
                                    m_pDevice->m_rasterizerState->GetDesc(),
                                    (const RosUmdRenderTargetView **)&m_pDevice->m_renderTargetViews[0],
                                    (const RosUmdShaderResourceView **)&m_pDevice->m_psResourceViews[0],
                                    m_numInputSignatureEntries,
                                    m_pInputSignatureEntries,
                                    m_numOutputSignatureEntries,
                                    m_pOutputSignatureEntries,
                                    0,
                                    NULL);
    if (m_pCompiler == NULL)
    {
        throw RosUmdException(E_OUTOFMEMORY);
    }

    HRESULT hr;
    if (FAILED(hr = m_pCompiler->Compile()))
    {
        throw RosUmdException(hr);
    }

    {
        m_hwShaderCodeSize = m_pCompiler->GetShaderCodeSize();
        assert(m_hwShaderCodeSize != 0);
           
        m_pDevice->CreateInternalBuffer(
            &m_hwShaderCode,
            ROUND_TO_PAGES(m_hwShaderCodeSize)); // TODO: for now, for easier debugging, round allocation size to PAGE size aligned.

        {
            D3D10DDI_MAPPED_SUBRESOURCE mappedSubRes = { 0 };

            m_hwShaderCode.Map(
                m_pDevice,
                0,
                D3D10_DDI_MAP_WRITE,
                0,
                &mappedSubRes);

            if (mappedSubRes.pData)
            {
                m_pCompiler->GetShaderCode(
                    mappedSubRes.pData, 
                    &m_vc4CoordinateShaderOffset);

                m_hwShaderCode.Unmap(
                    m_pDevice,
                    0);

                return;
            }
        }
    }

    throw RosUmdException(E_FAIL);
}
void
RosUmdResource::CalculateMemoryLayout(
    void)
{
    switch (m_resourceDimension)
    {
    case D3D10DDIRESOURCE_BUFFER:
        {
            m_hwLayout = RosHwLayout::Linear;

            // TODO(bhouse) Need mapping code from resource DXGI format to hw format
            m_hwFormat = RosHwFormat::X8;

            m_hwWidthPixels = m_mip0Info.TexelWidth;
            m_hwHeightPixels = m_mip0Info.TexelHeight;

            assert(m_hwFormat == RosHwFormat::X8);
            assert(m_hwHeightPixels == 1);
            m_hwSizeBytes = m_hwWidthPixels;
        }
    break;
    case D3D10DDIRESOURCE_TEXTURE2D:
        {
            if (m_usage == D3D10_DDI_USAGE_DEFAULT)
            {
                m_hwLayout = RosHwLayout::Tiled;
            }
            else
            {
                m_hwLayout = RosHwLayout::Linear;
            }

            // TODO(bhouse) Need mapping code from resource DXGI format to hw format
            m_hwFormat = RosHwFormat::X32;

            // Using system memory linear MipMap as example
            m_hwWidthPixels = m_mip0Info.TexelWidth;
            m_hwHeightPixels = m_mip0Info.TexelHeight;

            if (m_hwLayout == RosHwLayout::Linear)
            {
                m_hwSizeBytes = CPixel::ComputeMipMapSize(
                    m_hwWidthPixels,
                    m_hwHeightPixels,
                    m_mipLevels,
                    m_format);

                m_hwPitchBytes = CPixel::ComputeSurfaceStride(
                    m_hwWidthPixels,
                    CPixel::BytesPerPixel(m_format));
            }
            else
            {
                assert(m_hwLayout == RosHwLayout::Tiled);
                assert(m_mipLevels == 1);

                m_hwWidthTilePixels = 64;
                m_hwHeightTilePixels = 64;
                m_hwWidthTiles = (m_hwWidthPixels + m_hwWidthTilePixels - 1) / m_hwWidthTilePixels;
                m_hwHeightTiles = (m_hwHeightPixels + m_hwHeightTilePixels - 1) / m_hwHeightTilePixels;

                assert(m_hwFormat == RosHwFormat::X32);
                UINT sizeTileBytes = 64 * 64 * 4;

                m_hwSizeBytes = m_hwWidthTiles * m_hwWidthTiles * sizeTileBytes;
                m_hwPitchBytes = 0;
            }
        }
        break;
    case D3D10DDIRESOURCE_TEXTURE1D:
    case D3D10DDIRESOURCE_TEXTURE3D:
    case D3D10DDIRESOURCE_TEXTURECUBE:
        {
            throw RosUmdException(DXGI_DDI_ERR_UNSUPPORTED);
        }
        break;
    }
}
void
RosUmdResource::CalculateMemoryLayout(
    void)
{
    switch (m_resourceDimension)
    {
    case D3D10DDIRESOURCE_BUFFER:
        {
            m_hwLayout = RosHwLayout::Linear;

            // TODO(bhouse) Need mapping code from resource DXGI format to hw format
            m_hwFormat = RosHwFormat::X8;

            m_hwWidthPixels = m_mip0Info.TexelWidth;
            m_hwHeightPixels = m_mip0Info.TexelHeight;

            assert(m_hwFormat == RosHwFormat::X8);
            assert(m_hwHeightPixels == 1);
            m_hwSizeBytes = m_hwWidthPixels;
        }
    break;
    case D3D10DDIRESOURCE_TEXTURE2D:
        {
            if (m_usage == D3D10_DDI_USAGE_DEFAULT)
            {
                m_hwLayout = RosHwLayout::Tiled;
            }
            else
            {
                m_hwLayout = RosHwLayout::Linear;
            }

#if VC4

            // TODO[indyz]: Enable tiled render target
            if (m_bindFlags & D3D10_DDI_BIND_RENDER_TARGET)
            {
                m_hwLayout = RosHwLayout::Linear;
            }

#endif

            // TODO(bhouse) Need mapping code from resource DXGI format to hw format
            if (m_bindFlags & D3D10_DDI_BIND_DEPTH_STENCIL)
            {
                m_hwFormat = RosHwFormat::D24S8;
            }
            else
            {
                m_hwFormat = RosHwFormat::X8888;
            }

            // Using system memory linear MipMap as example
            m_hwWidthPixels = m_mip0Info.TexelWidth;
            m_hwHeightPixels = m_mip0Info.TexelHeight;

#if VC4
            // Align width and height to VC4_BINNING_TILE_PIXELS for binning
#endif

            m_hwWidthTilePixels = VC4_BINNING_TILE_PIXELS;
            m_hwHeightTilePixels = VC4_BINNING_TILE_PIXELS;
            m_hwWidthTiles = (m_hwWidthPixels + m_hwWidthTilePixels - 1) / m_hwWidthTilePixels;
            m_hwHeightTiles = (m_hwHeightPixels + m_hwHeightTilePixels - 1) / m_hwHeightTilePixels;
            m_hwWidthPixels = m_hwWidthTiles*m_hwWidthTilePixels;
            m_hwHeightPixels = m_hwHeightTiles*m_hwHeightTilePixels;

            if (m_hwLayout == RosHwLayout::Linear)
            {
                m_hwSizeBytes = CPixel::ComputeMipMapSize(
                    m_hwWidthPixels,
                    m_hwHeightPixels,
                    m_mipLevels,
                    m_format);

                m_hwPitchBytes = CPixel::ComputeSurfaceStride(
                    m_hwWidthPixels,
                    CPixel::BytesPerPixel(m_format));
            }
            else
            {
                assert(m_hwLayout == RosHwLayout::Tiled);
                assert(m_mipLevels == 1);

                assert((m_hwFormat == RosHwFormat::X8888) || (m_hwFormat == RosHwFormat::D24S8));
                UINT sizeTileBytes = 64 * 64 * 4;

                m_hwSizeBytes = m_hwWidthTiles * m_hwHeightTiles * sizeTileBytes;
                m_hwPitchBytes = 0;
            }
        }
        break;
    case D3D10DDIRESOURCE_TEXTURE1D:
    case D3D10DDIRESOURCE_TEXTURE3D:
    case D3D10DDIRESOURCE_TEXTURECUBE:
        {
            throw RosUmdException(DXGI_DDI_ERR_UNSUPPORTED);
        }
        break;
    }
}