/*
 * Copyright 2016-2017 Józef Kucia for CodeWeavers
 * Copyright 2020-2023 Philip Rebohle for Valve Corporation
 * Copyright 2020-2023 Joshua Ashton for Valve Corporation
 * Copyright 2020-2023 Hans-Kristian Arntzen for Valve Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#define VKD3D_DBG_CHANNEL VKD3D_DBG_CHANNEL_API
#include "d3d12_crosstest.h"

void test_sampler_feedback_resource_creation(void)
{
    D3D12_FEATURE_DATA_D3D12_OPTIONS7 features7;
    D3D12_HEAP_PROPERTIES heap_props;
    D3D12_HEAP_DESC heap_desc;
    D3D12_RESOURCE_DESC1 desc;
    ID3D12Resource *resource;
    ID3D12Device8 *device8;
    ID3D12Device *device;
    ID3D12Heap *heap;
    unsigned int i;
    UINT ref_count;
    HRESULT hr;

    static const struct test
    {
        unsigned int width, height, layers, levels;
        D3D12_MIP_REGION mip_region;
        D3D12_RESOURCE_FLAGS flags;
        HRESULT expected;
    } tests[] = {
        { 9, 11, 5, 3, { 4, 4, 1 }, D3D12_RESOURCE_FLAG_NONE, S_OK /* This is invalid, but runtime does not throw an error here. We'll just imply UAV flag for these formats. */ },
        { 9, 11, 5, 3, { 4, 4, 1 }, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, S_OK },
        { 13, 11, 5, 3, { 5, 5, 1 }, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, E_INVALIDARG /* POT error */ },
        { 9, 11, 5, 3, { 0, 0, 0 }, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, E_INVALIDARG /* Must be at least 4x4 */ },
        { 9, 11, 5, 3, { 4, 4, 2 }, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, E_INVALIDARG /* Depth field must be 0 or 1. */ },
        { 9, 11, 5, 3, { 4, 4, 0 }, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, S_OK /* This is fine. */ },
        { 9, 11, 5, 3, { 8, 8, 0 }, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, E_INVALIDARG /* Must not be more than half the size. */ },
    };

    device = create_device();
    if (!device)
        return;

    if (FAILED(ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS7, &features7, sizeof(features7))) ||
            features7.SamplerFeedbackTier < D3D12_SAMPLER_FEEDBACK_TIER_0_9)
    {
        skip("Sampler feedback not supported.\n");
        ID3D12Device_Release(device);
        return;
    }

    hr = ID3D12Device_QueryInterface(device, &IID_ID3D12Device8, (void **)&device8);
    ok(SUCCEEDED(hr), "Failed to query Device8, hr #%x.\n", hr);

    memset(&desc, 0, sizeof(desc));
    memset(&heap_props, 0, sizeof(heap_props));
    memset(&heap_desc, 0, sizeof(heap_desc));

    heap_props.Type = D3D12_HEAP_TYPE_DEFAULT;
    desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    desc.SampleDesc.Count = 1;
    desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;

    heap_desc.SizeInBytes = 1024 * 1024;
    heap_desc.Properties = heap_props;
    heap_desc.Flags = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED | D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES;
    hr = ID3D12Device_CreateHeap(device, &heap_desc, &IID_ID3D12Heap, (void **)&heap);
    ok(SUCCEEDED(hr), "Failed to create heap, hr #%x.\n", hr);

    for (i = 0; i < ARRAY_SIZE(tests); i++)
    {
        vkd3d_test_set_context("Test %u", i);
        desc.Width = tests[i].width;
        desc.Height = tests[i].height;
        desc.DepthOrArraySize = tests[i].layers;
        desc.MipLevels = tests[i].levels;
        desc.SamplerFeedbackMipRegion = tests[i].mip_region;
        desc.Flags = tests[i].flags;

        desc.Format = DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE;

        hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED,
            &desc, D3D12_RESOURCE_STATE_COMMON, NULL, NULL, &IID_ID3D12Resource, (void **)&resource);
        ok(hr == tests[i].expected, "Unexpected hr, expected #%x, got #%x.\n", tests[i].expected, hr);
        if (SUCCEEDED(hr))
            ID3D12Resource_Release(resource);

        hr = ID3D12Device8_CreatePlacedResource1(device8, heap, 0, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&resource);
        ok(hr == tests[i].expected, "Unexpected hr, expected #%x, got #%x.\n", tests[i].expected, hr);
        if (SUCCEEDED(hr))
            ID3D12Resource_Release(resource);

        desc.Format = DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE;

        hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED,
            &desc, D3D12_RESOURCE_STATE_COMMON, NULL, NULL, &IID_ID3D12Resource, (void **)&resource);
        ok(hr == tests[i].expected, "Unexpected hr, expected #%x, got #%x.\n", tests[i].expected, hr);
        if (SUCCEEDED(hr))
            ID3D12Resource_Release(resource);

        hr = ID3D12Device8_CreatePlacedResource1(device8, heap, 0, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&resource);
        ok(hr == tests[i].expected, "Unexpected hr, expected #%x, got #%x.\n", tests[i].expected, hr);
        if (SUCCEEDED(hr))
            ID3D12Resource_Release(resource);

        /* Feedback resources cannot be sparse themselves, there is no desc1 variant. */
    }
    vkd3d_test_set_context(NULL);

    ID3D12Device_Release(device);
    ID3D12Heap_Release(heap);
    ref_count = ID3D12Device8_Release(device8);
    ok(ref_count == 0, "Unexpected ref-count %u.\n", ref_count);
}

void test_sampler_feedback_format_features(void)
{
    D3D12_FEATURE_DATA_D3D12_OPTIONS7 features7;
    D3D12_FEATURE_DATA_FORMAT_SUPPORT format;
    ID3D12Device *device;
    unsigned int i;
    UINT ref_count;
    HRESULT hr;

    static const DXGI_FORMAT formats[] = {
        DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE,
        DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE,
    };

    device = create_device();
    if (!device)
        return;

    if (FAILED(ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_D3D12_OPTIONS7, &features7, sizeof(features7))) ||
        features7.SamplerFeedbackTier < D3D12_SAMPLER_FEEDBACK_TIER_0_9)
    {
        skip("Sampler feedback not supported.\n");
        ID3D12Device_Release(device);
        return;
    }

    for (i = 0; i < ARRAY_SIZE(formats); i++)
    {
        format.Format = formats[i];
        format.Support1 = UINT32_MAX;
        format.Support2 = UINT32_MAX;

        hr = ID3D12Device_CheckFeatureSupport(device, D3D12_FEATURE_FORMAT_SUPPORT, &format, sizeof(format));
        ok(SUCCEEDED(hr), "Failed to query for format features, hr #%x.\n", hr);

        ok(format.Support1 == (D3D12_FORMAT_SUPPORT1_TEXTURE2D | D3D12_FORMAT_SUPPORT1_MIP), "Unexpected feature support #%x.\n", format.Support1);
        ok(format.Support2 == D3D12_FORMAT_SUPPORT2_SAMPLER_FEEDBACK, "Unexpected feature support #%x.\n", format.Support2);
    }

    ref_count = ID3D12Device_Release(device);
    ok(ref_count == 0, "Unexpected ref-count %u.\n", ref_count);
}

static const BYTE cs_code_min_mip_level_non_array[] =
{
#if 0
    Texture2D<float> T : register(t0);
    SamplerState S : register(s0);
    FeedbackTexture2D<SAMPLER_FEEDBACK_MIN_MIP> FB : register(u0);

    cbuffer Cbuf : register(b0) { float2 uv; float level; };

    [numthreads(1, 1, 1)]
    void main()
    {
            FB.WriteSamplerFeedbackLevel(T, S, uv, level);
    }
#endif
        0x44, 0x58, 0x42, 0x43, 0xb0, 0x41, 0x58, 0x64, 0xd4, 0x11, 0xa1, 0x42, 0x88, 0x9e, 0xe5, 0x3a, 0x24, 0x41, 0xc6, 0x1b, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
        0x38, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0xa8, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
        0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x83, 0xff, 0x95, 0x2e, 0xed, 0x69, 0x3f, 0x0f, 0x82, 0xcc, 0x77, 0xdf, 0x0e, 0x0c, 0x08, 0x90, 0x44, 0x58, 0x49, 0x4c, 0xe0, 0x05, 0x00, 0x00, 0x65, 0x00, 0x05, 0x00,
        0x78, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x05, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xc8, 0x05, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00,
        0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19,
        0x1e, 0x04, 0x8b, 0x62, 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5,
        0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
        0x1b, 0x88, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0xda, 0x60, 0x08, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x12, 0x50, 0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
        0x13, 0x82, 0x60, 0x42, 0x20, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, 0x04, 0x93, 0x22, 0xe3,
        0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c, 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x6c, 0x23, 0x00, 0x25, 0x00, 0x14, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x21, 0x72, 0xcf, 0x70, 0xf9, 0x13, 0xf6,
        0x10, 0x92, 0x1f, 0x02, 0xcd, 0xb0, 0x10, 0x28, 0x28, 0x33, 0x00, 0x45, 0x01, 0xc3, 0x18, 0x73, 0xce, 0x39, 0x87, 0xd0, 0x51, 0xc3, 0xe5, 0x4f, 0xd8, 0x43, 0x48, 0x3e, 0xb7, 0x51, 0xc5, 0x4a,
        0x4c, 0x7e, 0x71, 0xdb, 0x88, 0x38, 0xe7, 0x9c, 0x42, 0xa8, 0x61, 0x06, 0xad, 0x39, 0x82, 0xa0, 0x18, 0x66, 0x90, 0x31, 0x1a, 0xb9, 0x81, 0x80, 0x99, 0xc2, 0x60, 0x1c, 0xd8, 0x21, 0x1c, 0xe6,
        0x61, 0x1e, 0xdc, 0x80, 0x16, 0xca, 0x01, 0x1f, 0xe8, 0xa1, 0x1e, 0xe4, 0xa1, 0x1c, 0xe4, 0x80, 0x14, 0xf8, 0xc0, 0x1c, 0xd8, 0xe1, 0x1d, 0xc2, 0x81, 0x1e, 0xfc, 0x40, 0x0f, 0xf4, 0xa0, 0x1d,
        0xd2, 0x01, 0x1e, 0xe6, 0xe1, 0x17, 0xe8, 0x21, 0x1f, 0xe0, 0xa1, 0x1c, 0x50, 0x30, 0x66, 0xb2, 0xc6, 0x81, 0x1d, 0xc2, 0x61, 0x1e, 0xe6, 0xc1, 0x0d, 0x68, 0xa1, 0x1c, 0xf0, 0x81, 0x1e, 0xea,
        0x41, 0x1e, 0xca, 0x41, 0x0e, 0x48, 0x81, 0x0f, 0xcc, 0x81, 0x1d, 0xde, 0x21, 0x1c, 0xe8, 0xc1, 0x0f, 0x90, 0x70, 0x22, 0xc9, 0x99, 0xb4, 0x71, 0x60, 0x87, 0x70, 0x98, 0x87, 0x79, 0x70, 0x03,
        0x53, 0x28, 0x87, 0x72, 0x20, 0x07, 0x71, 0x08, 0x87, 0x71, 0x58, 0x07, 0x5a, 0x28, 0x07, 0x7c, 0xa0, 0x87, 0x7a, 0x90, 0x87, 0x72, 0x90, 0x03, 0x52, 0xe0, 0x03, 0x38, 0xf0, 0x03, 0x14, 0x0c,
        0xa2, 0xc3, 0x08, 0xc2, 0x71, 0x04, 0x17, 0x50, 0x05, 0x12, 0xec, 0xa1, 0x7b, 0x93, 0x34, 0x45, 0x94, 0x30, 0xf9, 0x2c, 0xc0, 0x3c, 0x0b, 0x11, 0xb1, 0x13, 0x30, 0x11, 0x28, 0x18, 0x94, 0x01,
        0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30,
        0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a,
        0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07,
        0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60,
        0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x08, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x16, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38, 0x40, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x05,
        0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x1a, 0x25, 0x50, 0x0a, 0xe5, 0x50, 0x0c, 0x23, 0x00,
        0x45, 0x50, 0x12, 0x25, 0x52, 0x18, 0x85, 0x40, 0x6d, 0x04, 0x80, 0xe6, 0x0c, 0x00, 0xd5, 0x19, 0x00, 0xc2, 0x33, 0x00, 0xa4, 0x67, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00,
        0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0xe5, 0xc6, 0x45, 0x46, 0x26, 0x46, 0xc6, 0x85, 0x06, 0x06, 0x04, 0xa5, 0x0c, 0x86, 0x66,
        0xc6, 0x8c, 0x26, 0x2c, 0x46, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x06, 0x62, 0x82, 0x30, 0x14, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x0c, 0xc6, 0x06, 0x61, 0x30, 0x28, 0x8c, 0xcd, 0x4d, 0x10, 0x86,
        0x63, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x61, 0x40, 0x26, 0x08, 0xd3, 0x43, 0x60, 0x82, 0x30, 0x24, 0x13, 0x84, 0x41, 0xd9, 0x20, 0x2c, 0xcf, 0x86, 0x64, 0x61, 0x9a, 0x65, 0x19, 0x9c, 0x05, 0xda,
        0x10, 0x44, 0x13, 0x84, 0x0a, 0x9a, 0x20, 0x0c, 0xcb, 0x04, 0xa1, 0x71, 0x36, 0x08, 0xce, 0xb2, 0x61, 0x59, 0xa6, 0x66, 0x59, 0x06, 0xaa, 0xaa, 0x2a, 0x6b, 0x43, 0x70, 0x4d, 0x10, 0xb0, 0x68,
        0x82, 0x30, 0x30, 0x1b, 0x90, 0x25, 0x6b, 0x96, 0x65, 0xd0, 0x80, 0x0d, 0xc1, 0x36, 0x41, 0xd0, 0xa4, 0x0d, 0xc8, 0xd2, 0x35, 0xcb, 0x32, 0x2c, 0xc0, 0x86, 0xc0, 0xdb, 0x40, 0x48, 0x18, 0xf7,
        0x4d, 0x10, 0x04, 0x80, 0x44, 0x5b, 0x58, 0x9a, 0xdb, 0x04, 0x61, 0x68, 0x36, 0x0c, 0xc3, 0x30, 0x6c, 0x10, 0xc6, 0x80, 0x0c, 0x36, 0x14, 0x61, 0x20, 0x06, 0x00, 0x18, 0x94, 0x41, 0x15, 0x36,
        0x36, 0xbb, 0x36, 0x97, 0x34, 0xb2, 0x32, 0x37, 0xba, 0x29, 0x41, 0x50, 0x85, 0x0c, 0xcf, 0xc5, 0xae, 0x4c, 0x6e, 0x2e, 0xed, 0xcd, 0x6d, 0x4a, 0x40, 0x34, 0x21, 0xc3, 0x73, 0xb1, 0x0b, 0x63,
        0xb3, 0x2b, 0x93, 0x9b, 0x12, 0x18, 0x75, 0xc8, 0xf0, 0x5c, 0xe6, 0xd0, 0xc2, 0xc8, 0xca, 0xe4, 0x9a, 0xde, 0xc8, 0xca, 0xd8, 0xa6, 0x04, 0x49, 0x19, 0x32, 0x3c, 0x17, 0xb9, 0xb2, 0xb9, 0xb7,
        0x3a, 0xb9, 0xb1, 0xb2, 0xb9, 0x29, 0xc1, 0x57, 0x87, 0x0c, 0xcf, 0xa5, 0xcc, 0x8d, 0x4e, 0x2e, 0x0f, 0xea, 0x2d, 0xcd, 0x8d, 0x6e, 0x6e, 0x4a, 0x50, 0x06, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00,
        0x49, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6,
        0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8,
        0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11,
        0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89,
        0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37,
        0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81,
        0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c,
        0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc,
        0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87,
        0x77, 0xa8, 0x07, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x26, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, 0x41, 0x44, 0xa5, 0x03, 0x0c, 0x25,
        0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, 0x6d, 0x03, 0xd2, 0x70, 0xf9, 0xce, 0xe3, 0x0b, 0x11, 0x01, 0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, 0x58, 0xc0, 0x37, 0x5c, 0xbe, 0xf3, 0xf8, 0x56, 0x84, 0x4c,
        0x04, 0x0b, 0x30, 0xcf, 0x42, 0x44, 0x1f, 0x41, 0x0c, 0x01, 0x20, 0x28, 0x25, 0x51, 0x11, 0x8b, 0x01, 0x10, 0x0c, 0x80, 0x34, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
        0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x4a, 0xae, 0xec, 0x0a, 0x5c, 0x80, 0x48, 0x09, 0x8c, 0x00, 0x94, 0x41, 0x11, 0xd0, 0x99, 0x01, 0x00, 0x00, 0x00,
        0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0xe0, 0x60, 0x48, 0x31, 0x4d, 0xcd, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x38, 0x59, 0x52, 0x50, 0x94, 0x33, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x8e, 0xa6,
        0x14, 0x55, 0xf5, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0xb3, 0x2d, 0x85, 0x65, 0x41, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xb0, 0x74, 0x4b, 0x70, 0x8d, 0x26, 0x04, 0xc2, 0x68, 0x82, 0x00,
        0x8c, 0x26, 0x0c, 0xc1, 0x88, 0x41, 0x03, 0x80, 0x20, 0x18, 0x20, 0x62, 0xe0, 0x20, 0x87, 0x21, 0x04, 0x49, 0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const D3D12_SHADER_BYTECODE cs_code_min_mip_level_non_array_dxil = SHADER_BYTECODE(cs_code_min_mip_level_non_array);

static const BYTE cs_code_min_mip_level_array[] =
{
#if 0
    Texture2DArray<float> T : register(t0);
    SamplerState S : register(s0);
    FeedbackTexture2DArray<SAMPLER_FEEDBACK_MIN_MIP> FB : register(u0);

    cbuffer Cbuf : register(b0) { float2 uv; float level; float array; };

    [numthreads(1, 1, 1)]
    void main()
    {
            FB.WriteSamplerFeedbackLevel(T, S, float3(uv, array), level);
    }
#endif
        0x44, 0x58, 0x42, 0x43, 0xeb, 0x26, 0x3b, 0x21, 0x5f, 0x38, 0x29, 0x19, 0xcb, 0x42, 0xf4, 0x77, 0xf2, 0xe0, 0xdb, 0xe1, 0x01, 0x00, 0x00, 0x00, 0x34, 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
        0x38, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0xa8, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
        0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x5e, 0xf2, 0x91, 0x86, 0x68, 0x71, 0x16, 0x78, 0xdf, 0xe5, 0x43, 0x60, 0xcb, 0xdd, 0xcd, 0xba, 0x44, 0x58, 0x49, 0x4c, 0xf8, 0x05, 0x00, 0x00, 0x65, 0x00, 0x05, 0x00,
        0x7e, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x05, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xe0, 0x05, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00,
        0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19,
        0x1e, 0x04, 0x8b, 0x62, 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5,
        0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
        0x1b, 0x88, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0xda, 0x60, 0x08, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x12, 0x50, 0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
        0x13, 0x82, 0x60, 0x42, 0x20, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, 0x04, 0x93, 0x22, 0xe3,
        0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c, 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x6c, 0x23, 0x00, 0x25, 0x00, 0x14, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x21, 0x72, 0xcf, 0x70, 0xf9, 0x13, 0xf6,
        0x10, 0x92, 0x1f, 0x02, 0xcd, 0xb0, 0x10, 0x28, 0x28, 0x33, 0x00, 0x45, 0x01, 0xc3, 0x18, 0x73, 0xce, 0x39, 0x87, 0xd0, 0x51, 0xc3, 0xe5, 0x4f, 0xd8, 0x43, 0x48, 0x3e, 0xb7, 0x51, 0xc5, 0x4a,
        0x4c, 0x7e, 0x71, 0xdb, 0x88, 0x38, 0xe7, 0x9c, 0x42, 0xa8, 0x61, 0x06, 0xad, 0x39, 0x82, 0xa0, 0x18, 0x66, 0x90, 0x31, 0x1a, 0xb9, 0x81, 0x80, 0x99, 0xcc, 0x60, 0x1c, 0xd8, 0x21, 0x1c, 0xe6,
        0x61, 0x1e, 0xdc, 0x80, 0x16, 0xca, 0x01, 0x1f, 0xe8, 0xa1, 0x1e, 0xe4, 0xa1, 0x1c, 0xe4, 0x80, 0x14, 0x42, 0x41, 0x1e, 0xe4, 0x21, 0x1c, 0xf2, 0x81, 0x0f, 0xcc, 0x81, 0x1d, 0xde, 0x21, 0x1c,
        0xe8, 0xc1, 0x0f, 0xf4, 0x40, 0x0f, 0xda, 0x21, 0x1d, 0xe0, 0x61, 0x1e, 0x7e, 0x81, 0x1e, 0xf2, 0x01, 0x1e, 0xca, 0x01, 0x05, 0x63, 0xa6, 0x6d, 0x1c, 0xd8, 0x21, 0x1c, 0xe6, 0x61, 0x1e, 0xdc,
        0x80, 0x16, 0xca, 0x01, 0x1f, 0xe8, 0xa1, 0x1e, 0xe4, 0xa1, 0x1c, 0xe4, 0x80, 0x14, 0x42, 0x41, 0x1e, 0xe4, 0x21, 0x1c, 0xf2, 0x81, 0x0f, 0xcc, 0x81, 0x1d, 0xde, 0x21, 0x1c, 0xe8, 0xc1, 0x0f,
        0x90, 0x70, 0x22, 0xc9, 0x99, 0xbe, 0x71, 0x60, 0x87, 0x70, 0x98, 0x87, 0x79, 0x70, 0x03, 0x53, 0x28, 0x87, 0x72, 0x20, 0x07, 0x71, 0x08, 0x87, 0x71, 0x58, 0x07, 0x5a, 0x28, 0x07, 0x7c, 0xa0,
        0x87, 0x7a, 0x90, 0x87, 0x72, 0x90, 0x03, 0x52, 0x08, 0x05, 0x79, 0x90, 0x87, 0x70, 0xc8, 0x07, 0x3e, 0x80, 0x03, 0x3f, 0x40, 0xc1, 0x20, 0x3a, 0x8c, 0x20, 0x1c, 0x47, 0x70, 0x01, 0x55, 0xa0,
        0xc1, 0x9e, 0x43, 0xf7, 0x26, 0x69, 0x8a, 0x28, 0x61, 0xf2, 0x59, 0x80, 0x79, 0x16, 0x22, 0x62, 0x27, 0x60, 0x22, 0x50, 0x30, 0x28, 0x03, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87,
        0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d,
        0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07,
        0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20,
        0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76,
        0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x08, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x16, 0x20,
        0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38, 0x40, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x05, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
        0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x1a, 0x25, 0x50, 0x0a, 0xe5, 0x50, 0x0c, 0x23, 0x00, 0x25, 0x51, 0x24, 0x45, 0x50, 0x20, 0x85, 0x40,
        0x6d, 0x04, 0x80, 0xe6, 0x0c, 0x00, 0xd5, 0x19, 0x00, 0xc2, 0x33, 0x00, 0xa4, 0x67, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44,
        0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0xe5, 0xc6, 0x45, 0x46, 0x26, 0x46, 0xc6, 0x85, 0x06, 0x06, 0x04, 0xa5, 0x0c, 0x86, 0x66, 0xc6, 0x8c, 0x26, 0x2c, 0x46, 0x26, 0x65, 0x43,
        0x10, 0x4c, 0x10, 0x06, 0x62, 0x82, 0x30, 0x14, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x0c, 0xc6, 0x06, 0x61, 0x30, 0x28, 0x8c, 0xcd, 0x4d, 0x10, 0x86, 0x63, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x61, 0x40,
        0x26, 0x08, 0xd3, 0x43, 0x60, 0x82, 0x30, 0x24, 0x1b, 0x84, 0xc5, 0xd9, 0x90, 0x2c, 0x4c, 0xb3, 0x2c, 0x83, 0xb1, 0x3c, 0x1b, 0x02, 0x68, 0x82, 0x50, 0x41, 0x13, 0x84, 0x41, 0x99, 0x20, 0x34,
        0xce, 0x04, 0x61, 0x58, 0x36, 0x08, 0xd5, 0xb2, 0x61, 0x59, 0xa4, 0x66, 0x59, 0x86, 0x89, 0xa2, 0x28, 0x6b, 0x43, 0x70, 0x4d, 0x10, 0xb0, 0x68, 0x82, 0x30, 0x30, 0x1b, 0x90, 0x25, 0x6b, 0x96,
        0x65, 0xd0, 0x80, 0x0d, 0xc1, 0x36, 0x41, 0xd0, 0xa4, 0x0d, 0xc8, 0xd2, 0x35, 0xcb, 0x32, 0x2c, 0xc0, 0x86, 0xc0, 0xdb, 0x40, 0x44, 0x18, 0xf7, 0x4d, 0x10, 0x04, 0x80, 0x44, 0x5b, 0x58, 0x9a,
        0xdb, 0x04, 0x61, 0x68, 0x36, 0x0c, 0xc3, 0x30, 0x6c, 0x10, 0xc6, 0x80, 0x0c, 0x36, 0x14, 0x61, 0x20, 0x06, 0x00, 0x18, 0x94, 0x41, 0x15, 0x36, 0x36, 0xbb, 0x36, 0x97, 0x34, 0xb2, 0x32, 0x37,
        0xba, 0x29, 0x41, 0x50, 0x85, 0x0c, 0xcf, 0xc5, 0xae, 0x4c, 0x6e, 0x2e, 0xed, 0xcd, 0x6d, 0x4a, 0x40, 0x34, 0x21, 0xc3, 0x73, 0xb1, 0x0b, 0x63, 0xb3, 0x2b, 0x93, 0x9b, 0x12, 0x18, 0x75, 0xc8,
        0xf0, 0x5c, 0xe6, 0xd0, 0xc2, 0xc8, 0xca, 0xe4, 0x9a, 0xde, 0xc8, 0xca, 0xd8, 0xa6, 0x04, 0x49, 0x19, 0x32, 0x3c, 0x17, 0xb9, 0xb2, 0xb9, 0xb7, 0x3a, 0xb9, 0xb1, 0xb2, 0xb9, 0x29, 0xc1, 0x57,
        0x87, 0x0c, 0xcf, 0xa5, 0xcc, 0x8d, 0x4e, 0x2e, 0x0f, 0xea, 0x2d, 0xcd, 0x8d, 0x6e, 0x6e, 0x4a, 0x50, 0x06, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c,
        0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e,
        0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c,
        0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e,
        0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4,
        0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07,
        0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5,
        0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90,
        0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b,
        0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, 0x00, 0x00, 0x00, 0x00,
        0x71, 0x20, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x26, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, 0x41, 0x44, 0xa5, 0x03, 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, 0x6d, 0x03,
        0xd2, 0x70, 0xf9, 0xce, 0xe3, 0x0b, 0x11, 0x01, 0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, 0x58, 0xc0, 0x37, 0x5c, 0xbe, 0xf3, 0xf8, 0x56, 0x84, 0x4c, 0x04, 0x0b, 0x30, 0xcf, 0x42, 0x44, 0x1f, 0x41,
        0x0c, 0x01, 0x20, 0x28, 0x25, 0x51, 0x11, 0x8b, 0x01, 0x10, 0x0c, 0x80, 0x34, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00,
        0x05, 0x00, 0x00, 0x00, 0x34, 0x4a, 0xae, 0xec, 0x0a, 0x5c, 0x80, 0x48, 0x09, 0x8c, 0x00, 0x94, 0x41, 0x11, 0xd0, 0x99, 0x01, 0x00, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0xe0, 0x60,
        0x48, 0x31, 0x4d, 0xcd, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x38, 0x59, 0x52, 0x50, 0x94, 0x33, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x8e, 0xa6, 0x14, 0x55, 0xf5, 0x8c, 0x18, 0x24, 0x00, 0x08,
        0x82, 0x81, 0xb3, 0x2d, 0x85, 0x65, 0x41, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xb0, 0x74, 0x4b, 0x70, 0x8d, 0x26, 0x04, 0xc2, 0x68, 0x82, 0x00, 0x8c, 0x26, 0x0c, 0xc1, 0x68, 0x02, 0x31, 0x8c,
        0x18, 0x34, 0x00, 0x08, 0x82, 0x01, 0x32, 0x06, 0x4f, 0x82, 0x1c, 0x83, 0x10, 0x28, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00,
};
static const D3D12_SHADER_BYTECODE cs_code_min_mip_level_array_dxil = SHADER_BYTECODE(cs_code_min_mip_level_array);

static void test_sampler_feedback_min_mip_level_inner(bool arrayed)
{
    D3D12_FEATURE_DATA_D3D12_OPTIONS7 features7;
    D3D12_STATIC_SAMPLER_DESC static_sampler;
    struct test_context_desc context_desc;
    D3D12_DESCRIPTOR_RANGE desc_range[2];
    ID3D12DescriptorHeap *desc_heap_cpu;
    D3D12_ROOT_SIGNATURE_DESC rs_desc;
    ID3D12GraphicsCommandList1 *list1;
    D3D12_ROOT_PARAMETER rs_param[2];
    D3D12_HEAP_PROPERTIES heap_props;
    ID3D12DescriptorHeap *desc_heap;
    ID3D12Resource *feedback_copy;
    struct test_context context;
    struct resource_readback rb;
    D3D12_RESOURCE_DESC1 desc;
    ID3D12Resource *resource;
    ID3D12Resource *feedback;
    ID3D12Resource *resolve;
    ID3D12Device8 *device8;
    unsigned int x, y, i;
    HRESULT hr;

#define TEX_WIDTH 4096
#define TEX_HEIGHT 2048
#define MIP_REGION_WIDTH 128
#define MIP_REGION_HEIGHT 64
#define FEEDBACK_WIDTH (TEX_WIDTH / MIP_REGION_WIDTH)
#define FEEDBACK_HEIGHT (TEX_HEIGHT / MIP_REGION_HEIGHT)
#define TEX_MIP_LEVELS 6
#define TEX_MIP_LEVELS_VIEW (TEX_MIP_LEVELS - 1)
#define TEX_LAYERS 2

    static const int coords[][4] = {
        { 0, 0, 0, 0 },
        { TEX_WIDTH - MIP_REGION_WIDTH, 0, 0, 1 },
        { TEX_WIDTH - MIP_REGION_WIDTH, TEX_HEIGHT - MIP_REGION_HEIGHT, 0, 0 },
        { MIP_REGION_WIDTH, MIP_REGION_HEIGHT, 0, 1 },
        { 0, TEX_HEIGHT - MIP_REGION_HEIGHT, 0, 0 },

        { MIP_REGION_WIDTH * 20 + 3, MIP_REGION_HEIGHT * 17 + 1, 1, 1 },
        { MIP_REGION_WIDTH * 21 + 5, MIP_REGION_HEIGHT * 19 + 4, 2, 0 },
        { MIP_REGION_WIDTH * 22 + 7, MIP_REGION_HEIGHT * 25 + 2, 3, 1 },
        { MIP_REGION_WIDTH * 2, MIP_REGION_HEIGHT * 3, TEX_MIP_LEVELS_VIEW }
    };

    uint8_t expected_amd_style[TEX_LAYERS][FEEDBACK_HEIGHT][FEEDBACK_WIDTH];
    uint8_t expected_nv_style[TEX_LAYERS][FEEDBACK_HEIGHT][FEEDBACK_WIDTH];

    /* The spec allows for two styles of feedback. Either feedback is written once,
     * or it's written in a splat way so that the footprint touches (1 << LOD) x (1 << LOD) area in terms of mip regions.
     * See https://microsoft.github.io/DirectX-Specs/d3d/SamplerFeedback.html#minmip-feedback-map where it talks about:
     * "Note how the “01” may appear in the top left group of decoded texels, or in the top left texel only." */
    memset(expected_amd_style, 0xff, sizeof(expected_amd_style));
    memset(expected_nv_style, 0xff, sizeof(expected_nv_style));

    memset(&context_desc, 0, sizeof(context_desc));
    context_desc.no_pipeline = true;
    context_desc.no_render_target = true;
    context_desc.no_root_signature = true;
    if (!init_test_context(&context, &context_desc))
        return;

    {
        int inner_x, inner_y;
        int tile_x, tile_y;
        int view_levels;

        /* We technically have to provide all levels in the view (TIER_0_9),
         * but NV and AMD respect the SRV, Intel does not. */
        view_levels = is_intel_windows_device(context.device) ? TEX_MIP_LEVELS : TEX_MIP_LEVELS_VIEW;

        for (i = 0; i < ARRAY_SIZE(coords); i++)
        {
            int effective_lod = min(coords[i][2], view_levels - 1);
            int layer = arrayed ? coords[i][3] : 0;

            tile_x = (coords[i][0] % TEX_WIDTH) / MIP_REGION_WIDTH;
            tile_y = (coords[i][1] % TEX_HEIGHT) / MIP_REGION_HEIGHT;

            /* AMD just writes one texel here. */
            expected_amd_style[layer][tile_y][tile_x] = min(expected_amd_style[layer][tile_y][tile_x], effective_lod);

            /* NV writes a larger footprint. My working theory is that they write once to a hierarchical data structure which gets expanded in resolve. */
            tile_x &= ~((1 << effective_lod) - 1);
            tile_y &= ~((1 << effective_lod) - 1);
            for (inner_y = tile_y; inner_y < tile_y + (1 << effective_lod); inner_y++)
            {
                for (inner_x = tile_x; inner_x < tile_x + (1 << effective_lod); inner_x++)
                {
                    expected_nv_style[layer][inner_y][inner_x] = min(expected_nv_style[layer][inner_y][inner_x], effective_lod);
                }
            }
        }
    }

    if (FAILED(ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS7, &features7, sizeof(features7))) ||
            features7.SamplerFeedbackTier < D3D12_SAMPLER_FEEDBACK_TIER_0_9)
    {
        skip("Sampler feedback not supported.\n");
        destroy_test_context(&context);
        return;
    }

    hr = ID3D12Device_QueryInterface(context.device, &IID_ID3D12Device8, (void **)&device8);
    ok(SUCCEEDED(hr), "Failed to query Device8, hr #%x.\n", hr);
    hr = ID3D12GraphicsCommandList_QueryInterface(context.list, &IID_ID3D12GraphicsCommandList1, (void **)&list1);
    ok(SUCCEEDED(hr), "Failed to query GraphicsCommandList1, hr #%x.\n", hr);

    memset(&rs_desc, 0, sizeof(rs_desc));
    memset(desc_range, 0, sizeof(desc_range));
    memset(rs_param, 0, sizeof(rs_param));
    memset(&static_sampler, 0, sizeof(static_sampler));
    rs_desc.NumParameters = ARRAY_SIZE(rs_param);
    rs_desc.pParameters = rs_param;
    rs_desc.NumStaticSamplers = 1;
    rs_desc.pStaticSamplers = &static_sampler;

    static_sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
    static_sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
    static_sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
    static_sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
    static_sampler.MaxLOD = 1000.0f;

    rs_param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
    rs_param[0].DescriptorTable.NumDescriptorRanges = ARRAY_SIZE(desc_range);
    rs_param[0].DescriptorTable.pDescriptorRanges = desc_range;
    desc_range[0].NumDescriptors = 1;
    desc_range[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
    desc_range[1].NumDescriptors = 1;
    desc_range[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
    desc_range[1].OffsetInDescriptorsFromTableStart = 1;
    rs_param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
    rs_param[1].Constants.Num32BitValues = 4;

    create_root_signature(context.device, &rs_desc, &context.root_signature);
    context.pipeline_state = create_compute_pipeline_state(context.device, context.root_signature, arrayed ? cs_code_min_mip_level_array_dxil : cs_code_min_mip_level_non_array_dxil);
    ok(!!context.pipeline_state, "Failed to create PSO.\n");

    desc_heap = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2);
    desc_heap_cpu = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);

    resource = create_default_texture2d(context.device, TEX_WIDTH, TEX_HEIGHT, arrayed ? TEX_LAYERS : 1, TEX_MIP_LEVELS, DXGI_FORMAT_R8_UNORM, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
    resolve = create_default_texture2d(context.device, FEEDBACK_WIDTH, FEEDBACK_HEIGHT, arrayed ? TEX_LAYERS : 1, 1, DXGI_FORMAT_R8_UINT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_RESOLVE_DEST);

    memset(&desc, 0, sizeof(desc));
    memset(&heap_props, 0, sizeof(heap_props));

    heap_props.Type = D3D12_HEAP_TYPE_DEFAULT;
    desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    desc.SampleDesc.Count = 1;
    desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
    desc.Width = TEX_WIDTH;
    desc.Height = TEX_HEIGHT;
    desc.DepthOrArraySize = arrayed ? TEX_LAYERS : 1;
    desc.MipLevels = TEX_MIP_LEVELS;
    desc.SamplerFeedbackMipRegion.Width = MIP_REGION_WIDTH;
    desc.SamplerFeedbackMipRegion.Height = MIP_REGION_HEIGHT;
    desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
    desc.Format = DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE;
    hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, &desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, NULL, &IID_ID3D12Resource, (void **)&feedback);
    ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);
    hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, &desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, NULL, &IID_ID3D12Resource, (void **)&feedback_copy);
    ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);

    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback, ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap));
    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback, ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap_cpu));

    {
        D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc;
        memset(&srv_desc, 0, sizeof(srv_desc));
        srv_desc.Format = DXGI_FORMAT_R8_UNORM;
        srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
        if (arrayed)
        {
            srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
            srv_desc.Texture2DArray.MipLevels = TEX_MIP_LEVELS_VIEW; /* Verify that the SRV itself clamps the feedback that is written. */
            srv_desc.Texture2DArray.ArraySize = TEX_LAYERS;
        }
        else
        {
            srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
            srv_desc.Texture2D.MipLevels = TEX_MIP_LEVELS_VIEW; /* Verify that the SRV itself clamps the feedback that is written. */
        }
        ID3D12Device_CreateShaderResourceView(context.device, resource, &srv_desc, get_cpu_descriptor_handle(&context, desc_heap, 1));
    }

    ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &desc_heap);

    {
        UINT zeroes[4] = { 0 }; /* Clear value is ignored. The actual clear value is opaque, but after a resolve, it should be 0xff. */
        ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(context.list,
                ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heap),
                ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap_cpu),
                feedback, zeroes, 0, NULL);
        uav_barrier(context.list, feedback);
    }

    ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, context.root_signature);
    ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state);
    ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heap));

    for (i = 0; i < ARRAY_SIZE(coords); i++)
    {
        /* Test if implementations use RTE rule or floor(v + 0.5) rule. If RTE rule is used (it is on AMD and NV at least), 0.5 should snap down to 0 instead of 1. */
#define to_rte_center(v) (v % 2 == 0) ? ((float)(v) + 0.5f) : (float)(v)
        float normalized_coords[4] = { ((float)coords[i][0] + 0.5f) / TEX_WIDTH, ((float)coords[i][1] + 0.5f) / TEX_HEIGHT, (float)coords[i][2], to_rte_center(coords[i][3]) };
        ID3D12GraphicsCommandList_SetComputeRoot32BitConstants(context.list, 1, 4, normalized_coords, 0);
        ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1);
    }

    if (is_intel_windows_device(context.device))
    {
        /* CopyResource hangs GPU (yes, really ...) */
        transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
        ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve, UINT_MAX, 0, 0, feedback, UINT_MAX, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
    }
    else
    {
        transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
        /* CopyResource is allowed, but not by region. */
        ID3D12GraphicsCommandList_CopyResource(context.list, feedback_copy, feedback);
        transition_resource_state(context.list, feedback_copy, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);

        ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve, UINT_MAX, 0, 0, feedback_copy, UINT_MAX, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
    }
    transition_resource_state(context.list, resolve, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);


    for (i = 0; i < (arrayed ? TEX_LAYERS : 1); i++)
    {
        get_texture_readback_with_command_list(resolve, i, &rb, context.queue, context.list);

        for (y = 0; y < FEEDBACK_HEIGHT; y++)
        {
            for (x = 0; x < FEEDBACK_WIDTH; x++)
            {
                unsigned int value;
                value = get_readback_uint8(&rb, x, y);
                ok(value == expected_nv_style[i][y][x] || value == expected_amd_style[i][y][x],
                    "Coord %u, %u, %u: expected %u or %u, got %u.\n", x, y, i, expected_nv_style[i][y][x], expected_amd_style[i][y][x], value);
            }
        }

        release_resource_readback(&rb);
        reset_command_list(context.list, context.allocator);
    }

    ID3D12GraphicsCommandList1_Release(list1);
    ID3D12Resource_Release(resource);
    ID3D12Resource_Release(feedback);
    ID3D12Resource_Release(feedback_copy);
    ID3D12Resource_Release(resolve);
    ID3D12DescriptorHeap_Release(desc_heap);
    ID3D12DescriptorHeap_Release(desc_heap_cpu);
    ID3D12Device8_Release(device8);
    destroy_test_context(&context);
#undef TEX_WIDTH
#undef TEX_HEIGHT
#undef MIP_REGION_WIDTH
#undef MIP_REGION_HEIGHT
#undef FEEDBACK_WIDTH
#undef FEEDBACK_HEIGHT
#undef TEX_MIP_LEVELS
#undef TEX_MIP_LEVELS_VIEW
#undef TEX_LAYERS
}

void test_sampler_feedback_npot_min_mip_level(void)
{
    D3D12_FEATURE_DATA_D3D12_OPTIONS7 features7;
    D3D12_STATIC_SAMPLER_DESC static_sampler;
    struct test_context_desc context_desc;
    D3D12_DESCRIPTOR_RANGE desc_range[2];
    ID3D12DescriptorHeap *desc_heap_cpu;
    D3D12_ROOT_SIGNATURE_DESC rs_desc;
    ID3D12GraphicsCommandList1 *list1;
    D3D12_ROOT_PARAMETER rs_param[2];
    D3D12_HEAP_PROPERTIES heap_props;
    ID3D12DescriptorHeap *desc_heap;
    struct test_context context;
    struct resource_readback rb;
    D3D12_RESOURCE_DESC1 desc;
    ID3D12Resource *resource;
    ID3D12Resource *feedback;
    ID3D12Resource *resolve;
    ID3D12Device8 *device8;
    unsigned int x, y, i;
    HRESULT hr;

#define TEX_WIDTH (64 + 1)
#define TEX_HEIGHT (64 + 1)
#define MIP_REGION_WIDTH 4
#define MIP_REGION_HEIGHT 4
#define FEEDBACK_WIDTH ((TEX_WIDTH + MIP_REGION_WIDTH - 1) / MIP_REGION_WIDTH)
#define FEEDBACK_HEIGHT ((TEX_HEIGHT + MIP_REGION_HEIGHT - 1) / MIP_REGION_HEIGHT)
#define TEX_MIP_LEVELS 3
#define FEEDBACK_PAD 8

    /* Stay away from mip region edges to avoid tripping the conservative vkd3d-proton implementation.
     * To fix this, we need to add sampler information to dxil-spirv. */
    static const float coords[][3] = {
        /* Specifically chosen to expose bugged AMD behavior.
         * Should hit region (12, 12), but will hit region (11, 11) on AMD. */
        { 0.749f, 0.749f, 0.0f },
        /* Should hit region (4, 4) in LOD 1. */
        { 34.5f / TEX_WIDTH, 34.5f / TEX_HEIGHT, 1.0f },
        /* Should hit region (0, 0) in LOD 2. */
        { 28.0f / TEX_WIDTH, 28.0f / TEX_HEIGHT, 2.0f },
    };

    uint8_t expected[FEEDBACK_HEIGHT + FEEDBACK_PAD][FEEDBACK_WIDTH + FEEDBACK_PAD];

    memset(&context_desc, 0, sizeof(context_desc));
    context_desc.no_pipeline = true;
    context_desc.no_render_target = true;
    context_desc.no_root_signature = true;
    if (!init_test_context(&context, &context_desc))
        return;

    {
        unsigned int actual_feedback_height;
        unsigned int actual_feedback_width;
        int tile_x, tile_y;

        /* AMD is broken and rounds down. */
        if (is_amd_windows_device(context.device))
        {
            actual_feedback_height = TEX_HEIGHT / MIP_REGION_HEIGHT;
            actual_feedback_width = TEX_WIDTH / MIP_REGION_WIDTH;
        }
        else
        {
            actual_feedback_height = FEEDBACK_HEIGHT;
            actual_feedback_width = FEEDBACK_WIDTH;
        }

        for (y = 0; y < FEEDBACK_HEIGHT + FEEDBACK_PAD; y++)
            for (x = 0; x < FEEDBACK_WIDTH + FEEDBACK_PAD; x++)
                expected[y][x] = x < actual_feedback_width && y < actual_feedback_height ? 0xff : 0;

        for (i = 0; i < ARRAY_SIZE(coords); i++)
        {
            int effective_lod = min((int)coords[i][2], TEX_MIP_LEVELS - 1);

            if (is_amd_windows_device(context.device))
            {
                tile_x = (int)(coords[i][0] * actual_feedback_width);
                tile_y = (int)(coords[i][1] * actual_feedback_height);

                /* AMD just writes one texel here. */
                expected[tile_y][tile_x] = min(expected[tile_y][tile_x], effective_lod);
            }
            else
            {
                int tile_start_x, tile_start_y, tile_end_x, tile_end_y;
                float lo_coord_x, lo_coord_y, hi_coord_x, hi_coord_y;
                tile_x = (int)(coords[i][0] * (TEX_WIDTH >> effective_lod)) / MIP_REGION_WIDTH;
                tile_y = (int)(coords[i][1] * (TEX_HEIGHT >> effective_lod)) / MIP_REGION_HEIGHT;

                /* NPOT behavior on NV is ... very interesting here. It seems like we take the footprint of a region in the lower LOD domain, and reproject it over the higher domain.
                 * What happens here is that sometimes, LOD 1 touches 3x3 regions due to misalignment. This is similar issue that HiZ algorithms would run into. */

                lo_coord_x = (tile_x * MIP_REGION_WIDTH) * ((float)TEX_WIDTH / (float)(TEX_WIDTH >> effective_lod));
                lo_coord_y = (tile_y * MIP_REGION_WIDTH) * ((float)TEX_HEIGHT / (float)(TEX_HEIGHT >> effective_lod));
                hi_coord_x = ((tile_x + 1) * MIP_REGION_WIDTH) * ((float)TEX_WIDTH / (float)(TEX_WIDTH >> effective_lod));
                hi_coord_y = ((tile_y + 1) * MIP_REGION_WIDTH) * ((float)TEX_HEIGHT / (float)(TEX_HEIGHT >> effective_lod));

                tile_start_x = (int)floorf(lo_coord_x / MIP_REGION_WIDTH);
                tile_start_y = (int)floorf(lo_coord_y / MIP_REGION_HEIGHT);
                tile_end_x = (int)ceilf(hi_coord_x / MIP_REGION_WIDTH);
                tile_end_y = (int)ceilf(hi_coord_y / MIP_REGION_HEIGHT);

                for (tile_y = tile_start_y; tile_y < tile_end_y; tile_y++)
                    for (tile_x = tile_start_x; tile_x < tile_end_x; tile_x++)
                        expected[tile_y][tile_x] = min(expected[tile_y][tile_x], effective_lod);
            }
        }
    }

    if (FAILED(ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS7, &features7, sizeof(features7))) ||
        features7.SamplerFeedbackTier < D3D12_SAMPLER_FEEDBACK_TIER_0_9)
    {
        skip("Sampler feedback not supported.\n");
        destroy_test_context(&context);
        return;
    }

    hr = ID3D12Device_QueryInterface(context.device, &IID_ID3D12Device8, (void **)&device8);
    ok(SUCCEEDED(hr), "Failed to query Device8, hr #%x.\n", hr);
    hr = ID3D12GraphicsCommandList_QueryInterface(context.list, &IID_ID3D12GraphicsCommandList1, (void **)&list1);
    ok(SUCCEEDED(hr), "Failed to query GraphicsCommandList1, hr #%x.\n", hr);

    memset(&rs_desc, 0, sizeof(rs_desc));
    memset(desc_range, 0, sizeof(desc_range));
    memset(rs_param, 0, sizeof(rs_param));
    memset(&static_sampler, 0, sizeof(static_sampler));
    rs_desc.NumParameters = ARRAY_SIZE(rs_param);
    rs_desc.pParameters = rs_param;
    rs_desc.NumStaticSamplers = 1;
    rs_desc.pStaticSamplers = &static_sampler;

    static_sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
    static_sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
    static_sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
    static_sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
    static_sampler.MaxLOD = 1000.0f;

    rs_param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
    rs_param[0].DescriptorTable.NumDescriptorRanges = ARRAY_SIZE(desc_range);
    rs_param[0].DescriptorTable.pDescriptorRanges = desc_range;
    desc_range[0].NumDescriptors = 1;
    desc_range[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
    desc_range[1].NumDescriptors = 1;
    desc_range[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
    desc_range[1].OffsetInDescriptorsFromTableStart = 1;
    rs_param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
    rs_param[1].Constants.Num32BitValues = 3;

    create_root_signature(context.device, &rs_desc, &context.root_signature);
    context.pipeline_state = create_compute_pipeline_state(context.device, context.root_signature, cs_code_min_mip_level_non_array_dxil);
    ok(!!context.pipeline_state, "Failed to create PSO.\n");

    desc_heap = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2);
    desc_heap_cpu = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);

    resource = create_default_texture2d(context.device, TEX_WIDTH, TEX_HEIGHT, 1, TEX_MIP_LEVELS, DXGI_FORMAT_R8_UNORM, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
    /* Pad so we can study edge behavior. */
    resolve = create_default_texture2d(context.device, FEEDBACK_WIDTH + FEEDBACK_PAD, FEEDBACK_HEIGHT + FEEDBACK_PAD, 1, 1, DXGI_FORMAT_R8_UINT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_RESOLVE_DEST);

    memset(&desc, 0, sizeof(desc));
    memset(&heap_props, 0, sizeof(heap_props));

    heap_props.Type = D3D12_HEAP_TYPE_DEFAULT;
    desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    desc.SampleDesc.Count = 1;
    desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
    desc.Width = TEX_WIDTH;
    desc.Height = TEX_HEIGHT;
    desc.DepthOrArraySize = 1;
    desc.MipLevels = TEX_MIP_LEVELS;
    desc.SamplerFeedbackMipRegion.Width = MIP_REGION_WIDTH;
    desc.SamplerFeedbackMipRegion.Height = MIP_REGION_HEIGHT;
    desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
    desc.Format = DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE;
    hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, &desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, NULL, &IID_ID3D12Resource, (void **)&feedback);
    ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);

    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback, ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap));
    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback, ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap_cpu));

    {
        D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc;
        memset(&srv_desc, 0, sizeof(srv_desc));
        srv_desc.Format = DXGI_FORMAT_R8_UNORM;
        srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
        srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
        srv_desc.Texture2D.MipLevels = TEX_MIP_LEVELS; /* Verify that the SRV itself clamps the feedback that is written. */
        ID3D12Device_CreateShaderResourceView(context.device, resource, &srv_desc, get_cpu_descriptor_handle(&context, desc_heap, 1));
    }

    ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &desc_heap);

    {
        UINT zeroes[4] = { 0 }; /* Clear value is ignored. The actual clear value is opaque, but after a resolve, it should be 0xff. */
        ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(context.list,
            ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heap),
            ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap_cpu),
            feedback, zeroes, 0, NULL);
        uav_barrier(context.list, feedback);
    }

    ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, context.root_signature);
    ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state);
    ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heap));

    for (i = 0; i < ARRAY_SIZE(coords); i++)
    {
        ID3D12GraphicsCommandList_SetComputeRoot32BitConstants(context.list, 1, 3, coords[i], 0);
        ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1);
    }

    transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
    ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve, UINT_MAX, 0, 0, feedback, UINT_MAX, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
    transition_resource_state(context.list, resolve, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);

    get_texture_readback_with_command_list(resolve, 0, &rb, context.queue, context.list);

    for (y = 0; y < FEEDBACK_HEIGHT + FEEDBACK_PAD; y++)
    {
        for (x = 0; x < FEEDBACK_WIDTH + FEEDBACK_PAD; x++)
        {
            unsigned int value;
            value = get_readback_uint8(&rb, x, y);
            ok(value == expected[y][x], "Coord %u, %u: expected %u, got %u.\n", x, y, expected[y][x], value);
        }
    }

    release_resource_readback(&rb);
    reset_command_list(context.list, context.allocator);

    ID3D12GraphicsCommandList1_Release(list1);
    ID3D12Resource_Release(resource);
    ID3D12Resource_Release(feedback);
    ID3D12Resource_Release(resolve);
    ID3D12DescriptorHeap_Release(desc_heap);
    ID3D12DescriptorHeap_Release(desc_heap_cpu);
    ID3D12Device8_Release(device8);
    destroy_test_context(&context);
#undef TEX_WIDTH
#undef TEX_HEIGHT
#undef MIP_REGION_WIDTH
#undef MIP_REGION_HEIGHT
#undef FEEDBACK_WIDTH
#undef FEEDBACK_HEIGHT
#undef TEX_MIP_LEVELS
#undef TEX_MIP_LEVELS_VIEW
#undef TEX_LAYERS
#undef FEEDBACK_PAD
}

void test_sampler_feedback_min_mip_level(void)
{
    test_sampler_feedback_min_mip_level_inner(false);
}

void test_sampler_feedback_min_mip_level_array(void)
{
    test_sampler_feedback_min_mip_level_inner(true);
}

void test_sampler_feedback_decode_encode_min_mip(void)
{
#define MIP_REGIONS_X 10
#define MIP_REGIONS_Y 8
#define MIP_REGIONS_FLAT (MIP_REGIONS_X * MIP_REGIONS_Y)
#define MIP_REGION_WIDTH 8
#define MIP_REGION_HEIGHT 8
#define TEX_WIDTH (MIP_REGIONS_X * MIP_REGION_WIDTH)
#define TEX_HEIGHT (MIP_REGIONS_Y * MIP_REGION_HEIGHT)
#define LAYERS 4
    static const uint8_t reference_data[MIP_REGIONS_FLAT + 4 /* padding for array test */] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 31, 32, 0xff, 0xff, 0xff};
    D3D12_FEATURE_DATA_D3D12_OPTIONS7 features7;
    ID3D12Resource *feedback_min_mip_single;
    ID3D12Resource *feedback_min_mip_array;
    struct test_context_desc context_desc;
    ID3D12GraphicsCommandList1 *list1;
    D3D12_HEAP_PROPERTIES heap_props;
    struct test_context context;
    struct resource_readback rb;
    ID3D12Resource *resolve_tex;
    ID3D12Resource *upload_tex;
    D3D12_RESOURCE_DESC1 desc;
    ID3D12Resource *resolve;
    ID3D12Resource *upload;
    ID3D12Device8 *device8;
    unsigned int x, y, i;
    unsigned int iter;
    HRESULT hr;

    /* Funnily enough, resolve cannot be called in a COMPUTE or COPY queue. */

    memset(&context_desc, 0, sizeof(context_desc));
    context_desc.no_pipeline = true;
    context_desc.no_render_target = true;
    context_desc.no_root_signature = true;
    if (!init_test_context(&context, &context_desc))
        return;

    if (FAILED(ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS7, &features7, sizeof(features7))) ||
            features7.SamplerFeedbackTier < D3D12_SAMPLER_FEEDBACK_TIER_0_9)
    {
        skip("Sampler feedback not supported.\n");
        destroy_test_context(&context);
        return;
    }

    hr = ID3D12Device_QueryInterface(context.device, &IID_ID3D12Device8, (void **)&device8);
    ok(SUCCEEDED(hr), "Failed to query Device8, hr #%x.\n", hr);
    hr = ID3D12GraphicsCommandList_QueryInterface(context.list, &IID_ID3D12GraphicsCommandList1, (void **)&list1);
    ok(SUCCEEDED(hr), "Failed to query GraphicsCommandList1, hr #%x.\n", hr);

    memset(&desc, 0, sizeof(desc));
    memset(&heap_props, 0, sizeof(heap_props));

    heap_props.Type = D3D12_HEAP_TYPE_DEFAULT;
    desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    desc.SampleDesc.Count = 1;
    desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
    desc.Width = TEX_WIDTH;
    desc.Height = TEX_HEIGHT;
    desc.MipLevels = 4;
    desc.SamplerFeedbackMipRegion.Width = MIP_REGION_WIDTH;
    desc.SamplerFeedbackMipRegion.Height = MIP_REGION_HEIGHT;
    desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;

    desc.Format = DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE;

    desc.DepthOrArraySize = LAYERS;
    hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED,
            &desc, D3D12_RESOURCE_STATE_RESOLVE_DEST, NULL, NULL, &IID_ID3D12Resource, (void **)&feedback_min_mip_array);
    ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);

    desc.DepthOrArraySize = 1;
    hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED,
            &desc, D3D12_RESOURCE_STATE_RESOLVE_DEST, NULL, NULL, &IID_ID3D12Resource, (void **)&feedback_min_mip_single);
    ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);

    resolve = create_default_buffer(context.device, MIP_REGIONS_FLAT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_RESOLVE_DEST);
    resolve_tex = create_default_texture2d(context.device, MIP_REGIONS_X, MIP_REGIONS_Y, LAYERS, 1, DXGI_FORMAT_R8_UINT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_SOURCE);
    /* Check that we can store arbitrary data here. */
    upload = create_upload_buffer(context.device, MIP_REGIONS_FLAT, reference_data);
    upload_tex = create_default_texture2d(context.device, MIP_REGIONS_X, MIP_REGIONS_Y, LAYERS, 1, DXGI_FORMAT_R8_UINT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_DEST);

    /* BUFFER decode encode */
    {
        /* Spec carves out a special case for decoding / encoding with buffers. Must not be arrayed, and the docs seem to imply the buffer is tightly packed. */

        /* NV and AMD are non-compliant here. Spec says that transcoding should be transitive, but it is a lossy process. AMD's behavior makes slightly more sense than NV here. */

        /* DstX/Y for buffers are ignored on NV, but not AMD. Inherit NV behavior here, it's the only one that makes some kind of sense ... */
        /* SrcRect is ignored on NV (spec says it's not allowed for MIN_MIP), but not AMD. Inherit NV behavior here. */
        ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, feedback_min_mip_single, UINT_MAX, 0, 0, upload, 0, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_ENCODE_SAMPLER_FEEDBACK);
        transition_resource_state(context.list, feedback_min_mip_single, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
        ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve, 0, 0, 0, feedback_min_mip_single, UINT_MAX, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
        transition_resource_state(context.list, resolve, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
        get_buffer_readback_with_command_list(resolve, DXGI_FORMAT_R8_UINT, &rb, context.queue, context.list);
        for (i = 0; i < MIP_REGIONS_FLAT; i++)
        {
            uint8_t value = get_readback_uint8(&rb, i, 0);
            uint8_t expected;

            expected = reference_data[i];

            /* Arc behavior is also extremely unhinged. Just skip checking since it writes something to all 80 mip regions ... */

            if (is_nvidia_windows_device(context.device))
            {
                static const uint8_t reference_data_nv[MIP_REGIONS_FLAT] = { 0, 1, 1, 1, 3, 0xff, 0xff, 0xff, 0xff, 0xff, 1, 1, 1, 1, 3, 0xff, 0xff, 0xff };
                /* NV behavior is extremely weird and non-regular. There seems to be a mix of clamping and swapping out with 0xff going on ... */
                expected = reference_data_nv[i];
            }
            else if (is_amd_windows_device(context.device))
            {
                /* This is more reasonable. Theory is that each mip region gets a u32 mask of accessed mip levels. No bits sets -> not accessed.
                 * Anything outside the u32 range is considered not accessed. */
                if (expected >= 32)
                    expected = 0xff;
            }
            else
            {
                /* vkd3d-proton assumption. */
                if (expected > 14)
                    expected = 0xff;
            }

            bug_if(is_intel_windows_device(context.device))
                ok(value == expected, "Value %u: Expected %u, got %u\n", i, expected, value);
        }
        release_resource_readback(&rb);
        reset_command_list(context.list, context.allocator);
    }

    /* TEXTURE decode encode. Array mode is extremely weird. */
    for (iter = 0; iter < 2; iter++)
    {
        D3D12_RECT rect = { 1, 0, 2, 3 };
        D3D12_SUBRESOURCE_DATA subdata;
        bool resolve_all = iter == 1;

        subdata.RowPitch = MIP_REGIONS_X;
        subdata.SlicePitch = MIP_REGIONS_FLAT;
        for (i = 0; i < LAYERS; i++)
        {
            subdata.pData = reference_data + i;
            upload_texture_data_base(upload_tex, &subdata, i, 1, context.queue, context.list);
            reset_command_list(context.list, context.allocator);
        }

        transition_resource_state(context.list, upload_tex, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);

        /* On ENCODE, dst subresource is always -1, and source subresource index is the slice to resolve.
         * This implies two rules: We can only resolve layer N to layer N, and layer size of source and dest must be the same. */

        /* DstX and DstY are completely ignored here by both NV and AMD (wtf ...). The test assumes that DstX/DstY is interpreted as 0. */
        /* SrcRect is also silently ignored on both NV and AMD. */
        if (resolve_all)
            ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, feedback_min_mip_array, UINT_MAX, 1, 1, upload_tex, UINT_MAX, &rect, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_ENCODE_SAMPLER_FEEDBACK);
        else
        {
            for (i = 0; i < LAYERS; i++)
                ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, feedback_min_mip_array, UINT_MAX, 1, 1, upload_tex, i, &rect, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_ENCODE_SAMPLER_FEEDBACK);
        }

        transition_resource_state(context.list, feedback_min_mip_array, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
        transition_resource_state(context.list, upload_tex, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_COPY_DEST);
        transition_resource_state(context.list, resolve_tex, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RESOLVE_DEST);

        /* On DECODE, the rules flip, but here we test the other option which is to decode all array layers in one go. */
        if (resolve_all)
            ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve_tex, UINT_MAX, 2, 2, feedback_min_mip_array, UINT_MAX, &rect, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
        else
        {
            for (i = 0; i < LAYERS; i++)
                ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve_tex, i, 2, 2, feedback_min_mip_array, UINT_MAX, &rect, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
        }

        transition_resource_state(context.list, resolve_tex, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
        transition_resource_state(context.list, feedback_min_mip_array, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_RESOLVE_DEST);

        for (i = 0; i < LAYERS; i++)
        {
            bool has_non_zero_result = false;

            get_texture_readback_with_command_list(resolve_tex, i, &rb, context.queue, context.list);
            for (y = 0; y < MIP_REGIONS_Y; y++)
            {
                for (x = 0; x < MIP_REGIONS_X; x++)
                {
                    uint8_t value = get_readback_uint8(&rb, x, y);
                    uint8_t expected;

                    /* Make sure that NV cannot pass with all zero degenerate output. */
                    if (value)
                        has_non_zero_result = true;

                    expected = reference_data[y * MIP_REGIONS_X + x + i];

                    if (is_nvidia_windows_device(context.device))
                    {
                        /* Input is irregular to the point of being impossible to test. Only test conservatively, either we get a lower mip level, or not used at all. */
                        ok(value <= expected || value == 0xff, "Slice %u, value %u, %u: Expected %u, got %u\n", i, x, y, expected, value);
                    }
                    else
                    {
                        if (is_amd_windows_device(context.device))
                        {
                            /* This is more reasonable. Theory is that each mip region gets a u32 mask of accessed mip levels. No bits sets -> not accessed.
                             * Anything outside the u32 range is considered not accessed. */
                            if (expected >= 32)
                                expected = 0xff;
                        }
                        else
                        {
                            /* vkd3d-proton assumption. */
                            if (expected > 14)
                                expected = 0xff;
                        }

                        /* Accessing individual layers is broken on AMD. :( */
                        bug_if(is_intel_windows_device(context.device) || (!resolve_all && is_amd_windows_device(context.device)))
                            ok(value == expected, "Slice %u, value %u, %u: Expected %u, got %u\n", i, x, y, expected, value);
                    }
                }
            }

            bug_if(is_intel_windows_device(context.device) || (!resolve_all && is_amd_windows_device(context.device)))
                ok(has_non_zero_result, "Unexpected full zero result.\n");
            release_resource_readback(&rb);
            reset_command_list(context.list, context.allocator);
        }
    }

    ID3D12GraphicsCommandList1_Release(list1);
    ID3D12Resource_Release(feedback_min_mip_single);
    ID3D12Resource_Release(feedback_min_mip_array);
    ID3D12Resource_Release(upload_tex);
    ID3D12Resource_Release(resolve);
    ID3D12Resource_Release(resolve_tex);
    ID3D12Resource_Release(upload);
    ID3D12Device8_Release(device8);
    destroy_test_context(&context);
#undef MIP_REGIONS_X
#undef MIP_REGIONS_Y
#undef MIP_REGIONS_FLAT
#undef MIP_REGION_WIDTH
#undef MIP_REGION_HEIGHT
#undef TEX_WIDTH
#undef TEX_HEIGHT
#undef LAYERS
}

void test_sampler_feedback_decode_encode_mip_used(void)
{
#define MIP_REGIONS_X 16u
#define MIP_REGIONS_Y 16u
#define MIP_REGIONS_FLAT (MIP_REGIONS_X * MIP_REGIONS_Y)
#define MIP_REGION_WIDTH 8u
#define MIP_REGION_HEIGHT 8u
#define TEX_WIDTH (MIP_REGIONS_X * MIP_REGION_WIDTH)
#define TEX_HEIGHT (MIP_REGIONS_Y * MIP_REGION_HEIGHT)
#define LAYERS 4
#define LEVELS 3
    D3D12_FEATURE_DATA_D3D12_OPTIONS7 features7;
    struct test_context_desc context_desc;
    ID3D12GraphicsCommandList1 *list1;
    D3D12_HEAP_PROPERTIES heap_props;
    struct test_context context;
    struct resource_readback rb;
    ID3D12Resource *resolve_tex;
    ID3D12Resource *upload_tex;
    D3D12_RESOURCE_DESC1 desc;
    ID3D12Resource *feedback;
    unsigned int x, y, i, j;
    ID3D12Device8 *device8;
    HRESULT hr;

    /* Funnily enough, resolve cannot be called in a COMPUTE or COPY queue. */

    memset(&context_desc, 0, sizeof(context_desc));
    context_desc.no_pipeline = true;
    context_desc.no_render_target = true;
    context_desc.no_root_signature = true;
    if (!init_test_context(&context, &context_desc))
        return;

    if (FAILED(ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS7, &features7, sizeof(features7))) ||
        features7.SamplerFeedbackTier < D3D12_SAMPLER_FEEDBACK_TIER_0_9)
    {
        skip("Sampler feedback not supported.\n");
        destroy_test_context(&context);
        return;
    }

    hr = ID3D12Device_QueryInterface(context.device, &IID_ID3D12Device8, (void **)&device8);
    ok(SUCCEEDED(hr), "Failed to query Device8, hr #%x.\n", hr);
    hr = ID3D12GraphicsCommandList_QueryInterface(context.list, &IID_ID3D12GraphicsCommandList1, (void **)&list1);
    ok(SUCCEEDED(hr), "Failed to query GraphicsCommandList1, hr #%x.\n", hr);

    memset(&desc, 0, sizeof(desc));
    memset(&heap_props, 0, sizeof(heap_props));

    heap_props.Type = D3D12_HEAP_TYPE_DEFAULT;
    desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    desc.SampleDesc.Count = 1;
    desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
    desc.Width = TEX_WIDTH;
    desc.Height = TEX_HEIGHT;
    desc.MipLevels = LEVELS;
    desc.SamplerFeedbackMipRegion.Width = MIP_REGION_WIDTH;
    desc.SamplerFeedbackMipRegion.Height = MIP_REGION_HEIGHT;
    desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
    desc.Format = DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE;
    desc.DepthOrArraySize = LAYERS;
    hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED,
            &desc, D3D12_RESOURCE_STATE_RESOLVE_DEST, NULL, NULL, &IID_ID3D12Resource, (void **)&feedback);
    ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);

    /* Add padding so we can test offsets. */
    resolve_tex = create_default_texture2d(context.device, MIP_REGIONS_X * 4, MIP_REGIONS_Y * 4, LAYERS, LEVELS, DXGI_FORMAT_R8_UINT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_SOURCE);
    /* Check that we can store arbitrary data here. */
    upload_tex = create_default_texture2d(context.device, MIP_REGIONS_X, MIP_REGIONS_Y, LAYERS, LEVELS, DXGI_FORMAT_R8_UINT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_DEST);

    /* TEXTURE decode encode. Array mode is extremely weird. */

    for (i = 0; i < LAYERS * LEVELS; i++)
    {
        uint8_t reference_data[MIP_REGIONS_FLAT];
        D3D12_SUBRESOURCE_DATA subdata;

        for (j = 0; j < ARRAY_SIZE(reference_data); j++)
        {
            /* Test value 0, 255 and the values in between to see if there is consistent behavior in how TRUE is handled. */
            reference_data[j] = j + i;

            /* AMD and NV don't agree on what [1, 0xfe] means. For sanity, only test 0 and 0xff. */
            if (reference_data[j] & 4)
                reference_data[j] = 0xff;
            else
                reference_data[j] = 0;
        }
        subdata.pData = reference_data;
        subdata.RowPitch = MIP_REGIONS_X;
        subdata.SlicePitch = MIP_REGIONS_FLAT;
        upload_texture_data_base(upload_tex, &subdata, i, 1, context.queue, context.list);
        reset_command_list(context.list, context.allocator);
    }

    transition_resource_state(context.list, upload_tex, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);

    ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, feedback, UINT_MAX, 0, 0, upload_tex, UINT_MAX, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_ENCODE_SAMPLER_FEEDBACK);

    transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
    transition_resource_state(context.list, resolve_tex, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RESOLVE_DEST);

    /* DstX/DstY is completely broken. On NV, nothing happens. On AMD, shift is ignored. */
    ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve_tex, UINT_MAX, 0, 0, feedback, UINT_MAX, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
    transition_resource_state(context.list, resolve_tex, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
    transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_RESOLVE_DEST);

    for (i = 0; i < LAYERS * LEVELS; i++)
    {
        unsigned int level = i % LEVELS;
        get_texture_readback_with_command_list(resolve_tex, i, &rb, context.queue, context.list);
        for (y = 0; y < (MIP_REGIONS_Y >> level); y++)
        {
            for (x = 0; x < (MIP_REGIONS_X >> level); x++)
            {
                uint8_t value = get_readback_uint8(&rb, x, y);
                uint8_t expected = (y * MIP_REGIONS_X + x + i) & 4 ? 0xff : 0;
                ok(value == expected, "Subresource %u: (%u, %u): Expected %u, got %u.\n", i, x, y, expected, value);
            }
        }

        release_resource_readback(&rb);
        reset_command_list(context.list, context.allocator);
    }

    /* See what happens when we have mismatch subresources. This seems to work. */
    {
        /* Target Layer = 1, Level = 1 with Level = 0, Layer = 0 as source. This should not work, but it does.
         * Now DstX/Y works. */
        ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, feedback, LEVELS + 1, 1, 2, upload_tex, 0, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_ENCODE_SAMPLER_FEEDBACK);
        transition_resource_state(context.list, resolve_tex, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RESOLVE_DEST);
        transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);

        /* Resolve single layer (layer = 2, level = 0), then read it back. */
        ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve_tex, LEVELS * 2, 3, 4, feedback, LEVELS + 1, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
        transition_resource_state(context.list, resolve_tex, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
        transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_RESOLVE_DEST);

        get_texture_readback_with_command_list(resolve_tex, LEVELS * 2, &rb, context.queue, context.list);
        for (y = 0; y < (MIP_REGIONS_Y >> 1) - 2; y++)
        {
            for (x = 0; x < (MIP_REGIONS_X >> 1) - 1; x++)
            {
                uint8_t value = get_readback_uint8(&rb, x + 4, y + 6); /* We've shifted the image twice. */
                uint8_t expected = (y * MIP_REGIONS_X + x) & 4 ? 0xff : 0;

                /* This test only passes properly on AMD. */
                bug_if(is_nvidia_windows_device(context.device) || is_intel_windows_device(context.device))
                    ok(value == expected, "(%u, %u): Expected %u, got %u.\n", x, y, expected, value);
            }
        }

        release_resource_readback(&rb);
        reset_command_list(context.list, context.allocator);
    }

    /* Test source rect. */
    {
        D3D12_RECT decode_rect = { 1, 2, 9, 10 };
        D3D12_RECT encode_rect = { 4, 0, 5, 1 };
        ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, feedback, 0, decode_rect.left, decode_rect.top, upload_tex, 0, &encode_rect, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_ENCODE_SAMPLER_FEEDBACK);
        transition_resource_state(context.list, resolve_tex, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RESOLVE_DEST);
        transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);

        ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve_tex, 0, 0, 0, feedback, 0, &decode_rect, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
        transition_resource_state(context.list, resolve_tex, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
        transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_RESOLVE_DEST);

        get_texture_readback_with_command_list(resolve_tex, 0, &rb, context.queue, context.list);
        for (y = 0; y < MIP_REGIONS_Y; y++)
        {
            for (x = 0; x < MIP_REGIONS_X; x++)
            {
                uint8_t value = get_readback_uint8(&rb, x, y); /* We've shifted the image twice. */
                uint8_t expected;

                if (x == 0 && y == 0)
                    expected = (encode_rect.top * MIP_REGIONS_X + encode_rect.left) & 4 ? 0xff : 0;
                else if ((int)x < (decode_rect.right - decode_rect.left) && (int)y < (decode_rect.bottom - decode_rect.top))
                    expected = ((y + decode_rect.top) * MIP_REGIONS_X + (x + decode_rect.left)) & 4 ? 0xff : 0;
                else
                    expected = (y * MIP_REGIONS_X + x) & 4 ? 0xff : 0;

                bug_if(x == 0 && y == 0 && is_intel_windows_device(context.device))
                    ok(value == expected, "(%u, %u): Expected %u, got %u.\n", x, y, expected, value);
            }
        }

        release_resource_readback(&rb);
        reset_command_list(context.list, context.allocator);
    }

    /* With MIP_USED region both dst and src subresource matters. */

    ID3D12GraphicsCommandList1_Release(list1);
    ID3D12Resource_Release(feedback);
    ID3D12Resource_Release(upload_tex);
    ID3D12Resource_Release(resolve_tex);
    ID3D12Device8_Release(device8);
    destroy_test_context(&context);
#undef MIP_REGIONS_X
#undef MIP_REGIONS_Y
#undef MIP_REGIONS_FLAT
#undef MIP_REGION_WIDTH
#undef MIP_REGION_HEIGHT
#undef TEX_WIDTH
#undef TEX_HEIGHT
#undef LAYERS
#undef LEVELS
}

static const BYTE cs_code_level_used_region[] =
{
#if 0
    Texture2D<float> T : register(t0);
    SamplerState S : register(s0);
    FeedbackTexture2D<SAMPLER_FEEDBACK_MIP_REGION_USED> FB : register(u0);

    cbuffer Cbuf : register(b0) { float2 uv; float level; };

    [numthreads(1, 1, 1)]
    void main()
    {
            FB.WriteSamplerFeedbackLevel(T, S, uv, level);
    }
#endif
    0x44, 0x58, 0x42, 0x43, 0x26, 0x0c, 0x0c, 0xde, 0xd9, 0xe3, 0xf4, 0xb6, 0xd2, 0x79, 0xce, 0x60, 0x39, 0x07, 0xa2, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
    0x38, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0xa8, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
    0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x19, 0x0e, 0x31, 0x85, 0x97, 0xa6, 0x6b, 0xb3, 0x82, 0x97, 0xef, 0xf9, 0x23, 0x34, 0x3d, 0x36, 0x44, 0x58, 0x49, 0x4c, 0xe0, 0x05, 0x00, 0x00, 0x65, 0x00, 0x05, 0x00,
    0x78, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x05, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xc8, 0x05, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00,
    0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19,
    0x1e, 0x04, 0x8b, 0x62, 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5,
    0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
    0x1b, 0x88, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0xda, 0x60, 0x08, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x12, 0x50, 0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
    0x13, 0x82, 0x60, 0x42, 0x20, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, 0x04, 0x93, 0x22, 0xe3,
    0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c, 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x6c, 0x23, 0x00, 0x25, 0x00, 0x14, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x21, 0x72, 0xcf, 0x70, 0xf9, 0x13, 0xf6,
    0x10, 0x92, 0x1f, 0x02, 0xcd, 0xb0, 0x10, 0x28, 0x28, 0x33, 0x00, 0x45, 0x01, 0xc3, 0x18, 0x73, 0xce, 0x39, 0x87, 0xd0, 0x51, 0xc3, 0xe5, 0x4f, 0xd8, 0x43, 0x48, 0x3e, 0xb7, 0x51, 0xc5, 0x4a,
    0x4c, 0x7e, 0x71, 0xdb, 0x88, 0x38, 0xe7, 0x9c, 0x42, 0xa8, 0x61, 0x06, 0xad, 0x39, 0x82, 0xa0, 0x18, 0x66, 0x90, 0x31, 0x1a, 0xb9, 0x81, 0x80, 0x99, 0xc2, 0x60, 0x1c, 0xd8, 0x21, 0x1c, 0xe6,
    0x61, 0x1e, 0xdc, 0x80, 0x16, 0xca, 0x01, 0x1f, 0xe8, 0xa1, 0x1e, 0xe4, 0xa1, 0x1c, 0xe4, 0x80, 0x14, 0xf8, 0xc0, 0x1c, 0xd8, 0xe1, 0x1d, 0xc2, 0x81, 0x1e, 0xfc, 0x40, 0x0f, 0xf4, 0xa0, 0x1d,
    0xd2, 0x01, 0x1e, 0xe6, 0xe1, 0x17, 0xe8, 0x21, 0x1f, 0xe0, 0xa1, 0x1c, 0x50, 0x30, 0x66, 0xb2, 0xc6, 0x81, 0x1d, 0xc2, 0x61, 0x1e, 0xe6, 0xc1, 0x0d, 0x68, 0xa1, 0x1c, 0xf0, 0x81, 0x1e, 0xea,
    0x41, 0x1e, 0xca, 0x41, 0x0e, 0x48, 0x81, 0x0f, 0xcc, 0x81, 0x1d, 0xde, 0x21, 0x1c, 0xe8, 0xc1, 0x0f, 0x90, 0x70, 0x22, 0xc9, 0x99, 0xb4, 0x71, 0x60, 0x87, 0x70, 0x98, 0x87, 0x79, 0x70, 0x03,
    0x53, 0x28, 0x87, 0x72, 0x20, 0x07, 0x71, 0x08, 0x87, 0x71, 0x58, 0x07, 0x5a, 0x28, 0x07, 0x7c, 0xa0, 0x87, 0x7a, 0x90, 0x87, 0x72, 0x90, 0x03, 0x52, 0xe0, 0x83, 0x38, 0xf0, 0x03, 0x14, 0x0c,
    0xa2, 0xc3, 0x08, 0xc2, 0x71, 0x04, 0x17, 0x50, 0x05, 0x12, 0xec, 0xa1, 0x7b, 0x93, 0x34, 0x45, 0x94, 0x30, 0xf9, 0x2c, 0xc0, 0x3c, 0x0b, 0x11, 0xb1, 0x13, 0x30, 0x11, 0x28, 0x18, 0x94, 0x01,
    0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30,
    0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a,
    0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07,
    0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60,
    0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x08, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x16, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38, 0x40, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x05,
    0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x1a, 0x25, 0x50, 0x0a, 0xe5, 0x50, 0x0c, 0x23, 0x00,
    0x45, 0x50, 0x12, 0x25, 0x52, 0x18, 0x85, 0x40, 0x6d, 0x04, 0x80, 0xe6, 0x0c, 0x00, 0xd5, 0x19, 0x00, 0xc2, 0x33, 0x00, 0xa4, 0x67, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00,
    0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0xe5, 0xc6, 0x45, 0x46, 0x26, 0x46, 0xc6, 0x85, 0x06, 0x06, 0x04, 0xa5, 0x0c, 0x86, 0x66,
    0xc6, 0x8c, 0x26, 0x2c, 0x46, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x06, 0x62, 0x82, 0x30, 0x14, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x0c, 0xc6, 0x06, 0x61, 0x30, 0x28, 0x8c, 0xcd, 0x4d, 0x10, 0x86,
    0x63, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x61, 0x40, 0x26, 0x08, 0xd3, 0x43, 0x60, 0x82, 0x30, 0x24, 0x13, 0x84, 0x41, 0xd9, 0x20, 0x2c, 0xcf, 0x86, 0x64, 0x61, 0x9a, 0x65, 0x19, 0x9c, 0x05, 0xda,
    0x10, 0x44, 0x13, 0x84, 0x0a, 0x9a, 0x20, 0x0c, 0xcb, 0x04, 0xa1, 0x71, 0x36, 0x08, 0xce, 0xb0, 0x61, 0x59, 0xa6, 0x66, 0x59, 0x06, 0xaa, 0xaa, 0x2a, 0x6b, 0x43, 0x70, 0x4d, 0x10, 0xb0, 0x68,
    0x82, 0x30, 0x30, 0x1b, 0x90, 0x25, 0x6b, 0x96, 0x65, 0xd0, 0x80, 0x0d, 0xc1, 0x36, 0x41, 0xd0, 0xa4, 0x0d, 0xc8, 0xd2, 0x35, 0xcb, 0x32, 0x2c, 0xc0, 0x86, 0xc0, 0xdb, 0x40, 0x48, 0x18, 0xf7,
    0x4d, 0x10, 0x04, 0x80, 0x44, 0x5b, 0x58, 0x9a, 0xdb, 0x04, 0x61, 0x68, 0x36, 0x0c, 0xc3, 0x30, 0x6c, 0x10, 0xc6, 0x80, 0x0c, 0x36, 0x14, 0x61, 0x20, 0x06, 0x00, 0x18, 0x94, 0x41, 0x15, 0x36,
    0x36, 0xbb, 0x36, 0x97, 0x34, 0xb2, 0x32, 0x37, 0xba, 0x29, 0x41, 0x50, 0x85, 0x0c, 0xcf, 0xc5, 0xae, 0x4c, 0x6e, 0x2e, 0xed, 0xcd, 0x6d, 0x4a, 0x40, 0x34, 0x21, 0xc3, 0x73, 0xb1, 0x0b, 0x63,
    0xb3, 0x2b, 0x93, 0x9b, 0x12, 0x18, 0x75, 0xc8, 0xf0, 0x5c, 0xe6, 0xd0, 0xc2, 0xc8, 0xca, 0xe4, 0x9a, 0xde, 0xc8, 0xca, 0xd8, 0xa6, 0x04, 0x49, 0x19, 0x32, 0x3c, 0x17, 0xb9, 0xb2, 0xb9, 0xb7,
    0x3a, 0xb9, 0xb1, 0xb2, 0xb9, 0x29, 0xc1, 0x57, 0x87, 0x0c, 0xcf, 0xa5, 0xcc, 0x8d, 0x4e, 0x2e, 0x0f, 0xea, 0x2d, 0xcd, 0x8d, 0x6e, 0x6e, 0x4a, 0x50, 0x06, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00,
    0x49, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6,
    0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8,
    0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11,
    0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89,
    0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37,
    0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81,
    0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c,
    0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc,
    0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87,
    0x77, 0xa8, 0x07, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x26, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, 0x41, 0x44, 0xa5, 0x03, 0x0c, 0x25,
    0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, 0x6d, 0x03, 0xd2, 0x70, 0xf9, 0xce, 0xe3, 0x0b, 0x11, 0x01, 0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, 0x58, 0xc0, 0x37, 0x5c, 0xbe, 0xf3, 0xf8, 0x56, 0x84, 0x4c,
    0x04, 0x0b, 0x30, 0xcf, 0x42, 0x44, 0x1f, 0x41, 0x0c, 0x01, 0x20, 0x28, 0x25, 0x51, 0x11, 0x8b, 0x01, 0x10, 0x0c, 0x80, 0x34, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
    0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x4a, 0xae, 0xec, 0x0a, 0x5c, 0x80, 0x48, 0x09, 0x8c, 0x00, 0x94, 0x41, 0x11, 0xd0, 0x99, 0x01, 0x00, 0x00, 0x00,
    0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0xe0, 0x60, 0x48, 0x31, 0x4d, 0xcd, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x38, 0x59, 0x52, 0x50, 0x94, 0x33, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x8e, 0xa6,
    0x14, 0x55, 0xf5, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0xb3, 0x2d, 0x85, 0x65, 0x41, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xb0, 0x74, 0x4b, 0x70, 0x8d, 0x26, 0x04, 0xc2, 0x68, 0x82, 0x00,
    0x8c, 0x26, 0x0c, 0xc1, 0x88, 0x41, 0x03, 0x80, 0x20, 0x18, 0x20, 0x62, 0xe0, 0x20, 0x87, 0x21, 0x04, 0x49, 0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const D3D12_SHADER_BYTECODE cs_code_level_used_region_dxil = SHADER_BYTECODE(cs_code_level_used_region);

void test_sampler_feedback_mip_used_region_level(void)
{
    D3D12_FEATURE_DATA_D3D12_OPTIONS7 features7;
    D3D12_STATIC_SAMPLER_DESC static_sampler;
    struct test_context_desc context_desc;
    D3D12_DESCRIPTOR_RANGE desc_range[2];
    ID3D12DescriptorHeap *desc_heap_cpu;
    D3D12_ROOT_SIGNATURE_DESC rs_desc;
    ID3D12GraphicsCommandList1 *list1;
    D3D12_ROOT_PARAMETER rs_param[2];
    D3D12_HEAP_PROPERTIES heap_props;
    ID3D12DescriptorHeap *desc_heap;
    struct test_context context;
    struct resource_readback rb;
    D3D12_RESOURCE_DESC1 desc;
    ID3D12Resource *resource;
    ID3D12Resource *feedback;
    ID3D12Resource *resolve;
    ID3D12Device8 *device8;
    unsigned int x, y, i;
    HRESULT hr;

#define TEX_WIDTH 4096u
#define TEX_HEIGHT 2048u
#define MIP_REGION_WIDTH 128u
#define MIP_REGION_HEIGHT 64u
#define FEEDBACK_WIDTH (TEX_WIDTH / MIP_REGION_WIDTH)
#define FEEDBACK_HEIGHT (TEX_HEIGHT / MIP_REGION_HEIGHT)
#define TEX_MIP_LEVELS 6
#define TEX_MIP_LEVELS_VIEW TEX_MIP_LEVELS

    static const int coords[][3] = {
        { 0, 0, 0 },
        { TEX_WIDTH - MIP_REGION_WIDTH, 0, 0 },
        { TEX_WIDTH - MIP_REGION_WIDTH, TEX_HEIGHT - MIP_REGION_HEIGHT, 0 },
        { TEX_WIDTH + MIP_REGION_WIDTH, TEX_HEIGHT + MIP_REGION_HEIGHT, 0 },
        { 0, TEX_HEIGHT - MIP_REGION_HEIGHT, 0 },

        { MIP_REGION_WIDTH * 20 + 3, MIP_REGION_HEIGHT * 17 + 1, 1 },
        { MIP_REGION_WIDTH * 21 + 5, MIP_REGION_HEIGHT * 19 + 4, 2 },
        { MIP_REGION_WIDTH * 22 + 7, MIP_REGION_HEIGHT * 25 + 2, 3 },

        { MIP_REGION_WIDTH * 2, MIP_REGION_HEIGHT * 3, TEX_MIP_LEVELS_VIEW }
    };

    uint8_t expected_output[TEX_MIP_LEVELS][FEEDBACK_HEIGHT][FEEDBACK_WIDTH];
    memset(expected_output, 0, sizeof(expected_output));

    {
        int tile_x, tile_y;

        for (i = 0; i < ARRAY_SIZE(coords); i++)
        {
            int effective_lod = min(coords[i][2], TEX_MIP_LEVELS_VIEW - 1);

            tile_x = (coords[i][0] % TEX_WIDTH) / MIP_REGION_WIDTH;
            tile_y = (coords[i][1] % TEX_HEIGHT) / MIP_REGION_HEIGHT;
            tile_x >>= effective_lod;
            tile_y >>= effective_lod;

            expected_output[effective_lod][tile_y][tile_x] = 0xff;
        }
    }

    memset(&context_desc, 0, sizeof(context_desc));
    context_desc.no_pipeline = true;
    context_desc.no_render_target = true;
    context_desc.no_root_signature = true;
    if (!init_test_context(&context, &context_desc))
        return;

    if (FAILED(ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS7, &features7, sizeof(features7))) ||
        features7.SamplerFeedbackTier < D3D12_SAMPLER_FEEDBACK_TIER_0_9)
    {
        skip("Sampler feedback not supported.\n");
        destroy_test_context(&context);
        return;
    }

    hr = ID3D12Device_QueryInterface(context.device, &IID_ID3D12Device8, (void **)&device8);
    ok(SUCCEEDED(hr), "Failed to query Device8, hr #%x.\n", hr);
    hr = ID3D12GraphicsCommandList_QueryInterface(context.list, &IID_ID3D12GraphicsCommandList1, (void **)&list1);
    ok(SUCCEEDED(hr), "Failed to query GraphicsCommandList1, hr #%x.\n", hr);

    memset(&rs_desc, 0, sizeof(rs_desc));
    memset(desc_range, 0, sizeof(desc_range));
    memset(rs_param, 0, sizeof(rs_param));
    memset(&static_sampler, 0, sizeof(static_sampler));
    rs_desc.NumParameters = ARRAY_SIZE(rs_param);
    rs_desc.pParameters = rs_param;
    rs_desc.NumStaticSamplers = 1;
    rs_desc.pStaticSamplers = &static_sampler;

    static_sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
    static_sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
    static_sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
    static_sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
    static_sampler.MaxLOD = 1000.0f;

    rs_param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
    rs_param[0].DescriptorTable.NumDescriptorRanges = ARRAY_SIZE(desc_range);
    rs_param[0].DescriptorTable.pDescriptorRanges = desc_range;
    desc_range[0].NumDescriptors = 1;
    desc_range[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
    desc_range[1].NumDescriptors = 1;
    desc_range[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
    desc_range[1].OffsetInDescriptorsFromTableStart = 1;
    rs_param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
    rs_param[1].Constants.Num32BitValues = 3;

    create_root_signature(context.device, &rs_desc, &context.root_signature);
    context.pipeline_state = create_compute_pipeline_state(context.device, context.root_signature, cs_code_level_used_region_dxil);
    ok(!!context.pipeline_state, "Failed to create PSO.\n");

    desc_heap = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2);
    desc_heap_cpu = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);

    resource = create_default_texture2d(context.device, TEX_WIDTH, TEX_HEIGHT, 1, TEX_MIP_LEVELS, DXGI_FORMAT_R8_UNORM, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
    resolve = create_default_texture2d(context.device, FEEDBACK_WIDTH, FEEDBACK_HEIGHT, 1, TEX_MIP_LEVELS, DXGI_FORMAT_R8_UINT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_RESOLVE_DEST);

    memset(&desc, 0, sizeof(desc));
    memset(&heap_props, 0, sizeof(heap_props));

    heap_props.Type = D3D12_HEAP_TYPE_DEFAULT;
    desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    desc.SampleDesc.Count = 1;
    desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
    desc.Width = TEX_WIDTH;
    desc.Height = TEX_HEIGHT;
    desc.DepthOrArraySize = 1;
    desc.MipLevels = TEX_MIP_LEVELS;
    desc.SamplerFeedbackMipRegion.Width = MIP_REGION_WIDTH;
    desc.SamplerFeedbackMipRegion.Height = MIP_REGION_HEIGHT;
    desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
    desc.Format = DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE;
    hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, &desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, NULL, &IID_ID3D12Resource, (void **)&feedback);
    ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);

    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback, ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap));
    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback, ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap_cpu));

    {
        D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc;
        memset(&srv_desc, 0, sizeof(srv_desc));
        srv_desc.Format = DXGI_FORMAT_R8_UNORM;
        srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
        srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
        srv_desc.Texture2D.MipLevels = TEX_MIP_LEVELS_VIEW; /* Verify that the SRV itself clamps the feedback that is written. */
        ID3D12Device_CreateShaderResourceView(context.device, resource, &srv_desc, get_cpu_descriptor_handle(&context, desc_heap, 1));
    }

    ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &desc_heap);

    {
        UINT zeroes[4] = { 0x80 }; /* Clear value is ignored. The actual clear value is opaque, but after a resolve, it should be 0. */
        ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(context.list,
            ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heap),
            ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap_cpu),
            feedback, zeroes, 0, NULL);
        uav_barrier(context.list, feedback);
    }

    ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, context.root_signature);
    ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state);
    ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heap));

    for (i = 0; i < ARRAY_SIZE(coords); i++)
    {
        float normalized_coords[3] = { ((float)coords[i][0] + 0.5f) / TEX_WIDTH, ((float)coords[i][1] + 0.5f) / TEX_HEIGHT, (float)coords[i][2] };
        ID3D12GraphicsCommandList_SetComputeRoot32BitConstants(context.list, 1, 3, normalized_coords, 0);
        ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1);
    }

    transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
    ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve, UINT_MAX, 0, 0, feedback, UINT_MAX, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
    transition_resource_state(context.list, resolve, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);

    for (i = 0; i < TEX_MIP_LEVELS; i++)
    {
        get_texture_readback_with_command_list(resolve, i, &rb, context.queue, context.list);

        for (y = 0; y < (FEEDBACK_HEIGHT >> i); y++)
        {
            for (x = 0; x < (FEEDBACK_WIDTH >> i); x++)
            {
                unsigned int value;
                value = get_readback_uint8(&rb, x, y);

                /* NV seems to drop writes on the floor. Seems related to WRAP mode. */
                bug_if(is_nvidia_windows_device(context.device) && value == 0 && expected_output[i][y][x] == 0xff)
                    ok(value == expected_output[i][y][x], "Mip %u, Coord %u, %u: expected %u, got %u.\n", i, x, y, expected_output[i][y][x], value);
            }
        }
        release_resource_readback(&rb);
        reset_command_list(context.list, context.allocator);
    }

    ID3D12GraphicsCommandList1_Release(list1);
    ID3D12Resource_Release(resource);
    ID3D12Resource_Release(feedback);
    ID3D12Resource_Release(resolve);
    ID3D12DescriptorHeap_Release(desc_heap);
    ID3D12DescriptorHeap_Release(desc_heap_cpu);
    ID3D12Device8_Release(device8);
    destroy_test_context(&context);
#undef TEX_WIDTH
#undef TEX_HEIGHT
#undef MIP_REGION_WIDTH
#undef MIP_REGION_HEIGHT
#undef FEEDBACK_WIDTH
#undef FEEDBACK_HEIGHT
#undef TEX_MIP_LEVELS
#undef TEX_MIP_LEVELS_VIEW
}

void test_sampler_feedback_npot_used_region(void)
{
    /* Mip behavior for NPOT and feedback is ... something, because mip sizes in feedback domain must round up to make any sense.
     * This is very likely to break in some way on implementations. */
    D3D12_FEATURE_DATA_D3D12_OPTIONS7 features7;
    D3D12_STATIC_SAMPLER_DESC static_sampler;
    struct test_context_desc context_desc;
    D3D12_DESCRIPTOR_RANGE desc_range[2];
    ID3D12DescriptorHeap *desc_heap_cpu;
    D3D12_ROOT_SIGNATURE_DESC rs_desc;
    ID3D12GraphicsCommandList1 *list1;
    D3D12_ROOT_PARAMETER rs_param[2];
    D3D12_HEAP_PROPERTIES heap_props;
    ID3D12DescriptorHeap *desc_heap;
    unsigned int x, y, i, iteration;
    struct test_context context;
    struct resource_readback rb;
    D3D12_RESOURCE_DESC1 desc;
    ID3D12Resource *resource;
    ID3D12Resource *feedback;
    ID3D12Resource *resolve;
    ID3D12Device8 *device8;
    HRESULT hr;

    memset(&context_desc, 0, sizeof(context_desc));
    context_desc.no_pipeline = true;
    context_desc.no_render_target = true;
    context_desc.no_root_signature = true;
    if (!init_test_context(&context, &context_desc))
        return;

    if (FAILED(ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS7, &features7, sizeof(features7))) ||
        features7.SamplerFeedbackTier < D3D12_SAMPLER_FEEDBACK_TIER_0_9)
    {
        skip("Sampler feedback not supported.\n");
        destroy_test_context(&context);
        return;
    }

    hr = ID3D12Device_QueryInterface(context.device, &IID_ID3D12Device8, (void **)&device8);
    ok(SUCCEEDED(hr), "Failed to query Device8, hr #%x.\n", hr);
    hr = ID3D12GraphicsCommandList_QueryInterface(context.list, &IID_ID3D12GraphicsCommandList1, (void **)&list1);
    ok(SUCCEEDED(hr), "Failed to query GraphicsCommandList1, hr #%x.\n", hr);

    memset(&rs_desc, 0, sizeof(rs_desc));
    memset(desc_range, 0, sizeof(desc_range));
    memset(rs_param, 0, sizeof(rs_param));
    memset(&static_sampler, 0, sizeof(static_sampler));
    rs_desc.NumParameters = ARRAY_SIZE(rs_param);
    rs_desc.pParameters = rs_param;
    rs_desc.NumStaticSamplers = 1;
    rs_desc.pStaticSamplers = &static_sampler;

    static_sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
    static_sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
    static_sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
    static_sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
    static_sampler.MaxLOD = 1000.0f;

    rs_param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
    rs_param[0].DescriptorTable.NumDescriptorRanges = ARRAY_SIZE(desc_range);
    rs_param[0].DescriptorTable.pDescriptorRanges = desc_range;
    desc_range[0].NumDescriptors = 1;
    desc_range[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
    desc_range[1].NumDescriptors = 1;
    desc_range[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
    desc_range[1].OffsetInDescriptorsFromTableStart = 1;
    rs_param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
    rs_param[1].Constants.Num32BitValues = 3;

    create_root_signature(context.device, &rs_desc, &context.root_signature);
    context.pipeline_state = create_compute_pipeline_state(context.device, context.root_signature, cs_code_level_used_region_dxil);
    ok(!!context.pipeline_state, "Failed to create PSO.\n");

    desc_heap = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2);
    desc_heap_cpu = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);

    /* For MinMip, there's only one level, and after converting to integer coordinates in Mip0 space, we just divide by MipRegion to get the integer coordiate in that map.
     * This case isn't very interesting to test, but MipUsed region definitely is. The interesting part is exactly how address computation works.
     * The documentation is not exactly helpful here, it seems to imply some kind of re-stretching so that the lower MIP fits into the higher MIP grid, but that only makes sense for MinMip.
     * https://microsoft.github.io/DirectX-Specs/d3d/SamplerFeedback.html#example-of-non-power-of-two-feedback-maps-behavior */

    /* Exhaustively test every possible width/height in the range without a POT band to check for weird corner cases. */
    for (iteration = 15; iteration < 32; iteration += 2)
    {
#define MIP_REGION_WIDTH 4
#define MIP_REGION_HEIGHT 4
#define MAX_FEEDBACK_WIDTH 8
#define MAX_FEEDBACK_HEIGHT 8
#define TEX_MIP_LEVELS 3
        unsigned int TEX_WIDTH = iteration;
        unsigned int TEX_HEIGHT = iteration + 1;
        unsigned int FEEDBACK_WIDTH = (TEX_WIDTH + MIP_REGION_WIDTH - 1) / MIP_REGION_WIDTH;
        unsigned int FEEDBACK_HEIGHT = (TEX_HEIGHT + MIP_REGION_HEIGHT - 1) / MIP_REGION_HEIGHT;

        /* Docs says that when resolving, the feedback domain must be able to hold the number of mips. Feedback size is 5x5 here, so 3 mips is max.
         * Another question is how mip sizes work. Due to round-up behavior, it's possible that mip size computation is not simple max(Size0 >> LOD, 1) */

        const int coords[][3] = {
            { TEX_WIDTH - 1, TEX_HEIGHT - 1, 0 },
            { TEX_WIDTH - 1, TEX_HEIGHT - 1, 1 },
            { TEX_WIDTH - 1, TEX_HEIGHT - 1, 2 },
        };

        uint8_t expected_output[TEX_MIP_LEVELS][MAX_FEEDBACK_HEIGHT][MAX_FEEDBACK_WIDTH];
        memset(expected_output, 0, sizeof(expected_output));

        vkd3d_test_set_context("Base resolution %u x %u", TEX_WIDTH, TEX_HEIGHT);

        {
            int tile_x, tile_y;

            for (i = 0; i < ARRAY_SIZE(coords); i++)
            {
                int effective_lod = min(coords[i][2], TEX_MIP_LEVELS - 1);
                float u, v;
                int iu, iv;

                /* Normalized coord. */
                u = (coords[i][0] + 0.5f) / TEX_WIDTH;
                v = (coords[i][1] + 0.5f) / TEX_HEIGHT;

                if (is_amd_windows_device(context.device))
                {
                    /* AMD behavior is esoteric as well. AMD behavior seems to be that the feedback image is actually created in feedback resolution (rounded down!).
                     * We compute coordinates for the feedback resolution directly instead. */
                    int feedback_width_floor = (TEX_WIDTH / MIP_REGION_WIDTH) >> effective_lod;
                    int feedback_height_floor = (TEX_HEIGHT / MIP_REGION_HEIGHT) >> effective_lod;

                    /* Compute actual coordinate we'll access in the feedback texture directly (this is very wrong ...). */
                    u *= (float)feedback_width_floor;
                    v *= (float)feedback_height_floor;

                    tile_x = (int)u;
                    tile_y = (int)v;

                    expected_output[effective_lod][tile_y][tile_x] = 0xff;
                }
                else
                {
                    /* For MipUsed, the rules seem to be that we must compute the integer coordinate in the mip we're accessing,
                     * then convert that to a mip region coordinate. This is subtly different than MinMip. */

                    /* Compute actual coordinate we'll access. */
                    u *= (float)(TEX_WIDTH >> effective_lod);
                    v *= (float)(TEX_HEIGHT >> effective_lod);

                    iu = (int)u;
                    iv = (int)v;

                    tile_x = iu / MIP_REGION_WIDTH;
                    tile_y = iv / MIP_REGION_HEIGHT;

                    /* NPOT is fundamentally broken with MipUsedRegion. We are normally supposed to round up to get the size of mip level 1,
                     * but after that, we get round down behavior in the mip chain, so we can end up with a 5x5 feedback texture that has 2x2 mip regions in level 1,
                     * However, LOD 1 in the base texture can be e.g. 20x20. We are able to access pixels 8 and 9 in the 10x10 LOD1. Feedback for this pixel will be discarded
                     * since it's out of bounds in feedback space ... (._.). As long as the resolve destination texture is padded, it will show up in results. */
                    expected_output[effective_lod][tile_y][tile_x] = 0xff;

                    /* vkd3d-proton tries to match NV behavior here. */
                }
            }
        }

        resource = create_default_texture2d(context.device, TEX_WIDTH, TEX_HEIGHT, 1, TEX_MIP_LEVELS, DXGI_FORMAT_R8_UNORM, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
        /* Padding the destination texture is necessary to get all information. */
        resolve = create_default_texture2d(context.device, FEEDBACK_WIDTH * 2, FEEDBACK_HEIGHT * 2, 1, TEX_MIP_LEVELS, DXGI_FORMAT_R8_UINT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_RESOLVE_DEST);

        memset(&desc, 0, sizeof(desc));
        memset(&heap_props, 0, sizeof(heap_props));

        heap_props.Type = D3D12_HEAP_TYPE_DEFAULT;
        desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
        desc.SampleDesc.Count = 1;
        desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
        desc.Width = TEX_WIDTH;
        desc.Height = TEX_HEIGHT;
        desc.DepthOrArraySize = 1;
        desc.MipLevels = TEX_MIP_LEVELS;
        desc.SamplerFeedbackMipRegion.Width = MIP_REGION_WIDTH;
        desc.SamplerFeedbackMipRegion.Height = MIP_REGION_HEIGHT;
        desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
        desc.Format = DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE;
        hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, &desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, NULL, &IID_ID3D12Resource, (void **)&feedback);
        ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);

        ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback, ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap));
        ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback, ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap_cpu));

        {
            D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc;
            memset(&srv_desc, 0, sizeof(srv_desc));
            srv_desc.Format = DXGI_FORMAT_R8_UNORM;
            srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
            srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
            srv_desc.Texture2D.MipLevels = TEX_MIP_LEVELS; /* Verify that the SRV itself clamps the feedback that is written. */
            ID3D12Device_CreateShaderResourceView(context.device, resource, &srv_desc, get_cpu_descriptor_handle(&context, desc_heap, 1));
        }

        ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &desc_heap);

        {
            UINT zeroes[4] = { 0x80 }; /* Clear value is ignored. The actual clear value is opaque, but after a resolve, it should be 0. */
            ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(context.list,
                ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heap),
                ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap_cpu),
                feedback, zeroes, 0, NULL);
            uav_barrier(context.list, feedback);
        }

        ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, context.root_signature);
        ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state);
        ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heap));

        for (i = 0; i < ARRAY_SIZE(coords); i++)
        {
            float normalized_coords[3] = { ((float)coords[i][0] + 0.5f) / TEX_WIDTH, ((float)coords[i][1] + 0.5f) / TEX_HEIGHT, (float)coords[i][2] };
            ID3D12GraphicsCommandList_SetComputeRoot32BitConstants(context.list, 1, 3, normalized_coords, 0);
            ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1);
        }

        transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
        ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve, UINT_MAX, 0, 0, feedback, UINT_MAX, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
        transition_resource_state(context.list, resolve, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);

        for (i = 0; i < TEX_MIP_LEVELS; i++)
        {
            get_texture_readback_with_command_list(resolve, i, &rb, context.queue, context.list);

            for (y = 0; y < ((TEX_HEIGHT >> i) + MIP_REGION_HEIGHT - 1) / MIP_REGION_HEIGHT; y++)
            {
                for (x = 0; x < ((TEX_WIDTH >> i) + MIP_REGION_WIDTH - 1) / MIP_REGION_WIDTH; x++)
                {
                    unsigned int value;
                    value = get_readback_uint8(&rb, x, y);

                    /* Intel has many stray writes that should not exist. */
                    bug_if(is_intel_windows_device(context.device) && value && expected_output[i][y][x] == 0)
                        ok(value == expected_output[i][y][x], "Mip %u, Coord %u, %u: expected %u, got %u.\n", i, x, y, expected_output[i][y][x], value);
                }
            }
            release_resource_readback(&rb);
            reset_command_list(context.list, context.allocator);
        }

        ID3D12Resource_Release(resource);
        ID3D12Resource_Release(feedback);
        ID3D12Resource_Release(resolve);
    }

    vkd3d_test_set_context(NULL);
    ID3D12GraphicsCommandList1_Release(list1);
    ID3D12DescriptorHeap_Release(desc_heap);
    ID3D12DescriptorHeap_Release(desc_heap_cpu);
    ID3D12Device8_Release(device8);
    destroy_test_context(&context);
#undef MIP_REGION_WIDTH
#undef MIP_REGION_HEIGHT
#undef TEX_MIP_LEVELS
}

void test_sampler_feedback_grad(void)
{
    D3D12_FEATURE_DATA_D3D12_OPTIONS7 features7;
    D3D12_DESCRIPTOR_RANGE desc_range_sampler;
    struct test_context_desc context_desc;
    D3D12_DESCRIPTOR_RANGE desc_range[2];
    ID3D12DescriptorHeap *desc_heap_cpu;
    ID3D12DescriptorHeap *desc_heaps[2];
    D3D12_ROOT_SIGNATURE_DESC rs_desc;
    ID3D12GraphicsCommandList1 *list1;
    D3D12_ROOT_PARAMETER rs_param[3];
    D3D12_HEAP_PROPERTIES heap_props;
    ID3D12Resource *feedback_used;
    ID3D12Resource *feedback_min;
    ID3D12Resource *resolve_used;
    ID3D12Resource *resolve_min;
    struct test_context context;
    struct resource_readback rb;
    D3D12_RESOURCE_DESC1 desc;
    ID3D12Resource *resource;
    ID3D12Device8 *device8;
    unsigned int x, y, i;
    HRESULT hr;

    static const BYTE cs_code[] =
    {
#if 0
    Texture2D<float> T : register(t0);
    SamplerState S : register(s0);
    FeedbackTexture2D<SAMPLER_FEEDBACK_MIP_REGION_USED> FB : register(u0);
    FeedbackTexture2D<SAMPLER_FEEDBACK_MIN_MIP> FB2 : register(u1);

    cbuffer Cbuf : register(b0) { float2 uv, dx, dy; };

    [numthreads(1, 1, 1)]
    void main()
    {
            FB.WriteSamplerFeedbackGrad(T, S, uv, dx, dy);
            FB2.WriteSamplerFeedbackGrad(T, S, uv, dx, dy);
    }
#endif
        0x44, 0x58, 0x42, 0x43, 0x3a, 0x59, 0x5d, 0xdd, 0xd4, 0x5e, 0xef, 0x36, 0x23, 0x6e, 0x31, 0x37, 0xce, 0x3c, 0x25, 0x01, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
        0x38, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0xc0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
        0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0xb6, 0x84, 0x01,
        0x10, 0x55, 0xfb, 0x8d, 0x04, 0xd8, 0xec, 0x4c, 0x82, 0xd0, 0x36, 0x15, 0x44, 0x58, 0x49, 0x4c, 0x90, 0x06, 0x00, 0x00, 0x65, 0x00, 0x05, 0x00, 0xa4, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c,
        0x05, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x78, 0x06, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x9b, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00,
        0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x14, 0x45, 0x02,
        0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90,
        0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x88, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07,
        0x40, 0xda, 0x60, 0x08, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x12, 0x50, 0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x00, 0x00, 0x00,
        0x89, 0x20, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c,
        0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x74, 0x23, 0x00, 0x25, 0x00, 0x14, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x21, 0x72, 0xcf, 0x70, 0xf9, 0x13, 0xf6, 0x10, 0x92, 0x1f, 0x02, 0xcd, 0xb0, 0x10, 0x28,
        0x28, 0x33, 0x00, 0x05, 0x02, 0xc3, 0x18, 0x73, 0xce, 0x39, 0xe7, 0x9c, 0x73, 0xce, 0x21, 0x74, 0xd4, 0x70, 0xf9, 0x13, 0xf6, 0x10, 0x92, 0xcf, 0x6d, 0x54, 0xb1, 0x12, 0x93, 0x5f, 0xdc, 0x36,
        0x22, 0xce, 0x39, 0xa7, 0x10, 0x6a, 0x98, 0x41, 0x6b, 0x8e, 0x20, 0x28, 0x86, 0x19, 0x64, 0x8c, 0x46, 0x6e, 0x20, 0x60, 0xa6, 0x30, 0x18, 0x07, 0x76, 0x08, 0x87, 0x79, 0x98, 0x07, 0x37, 0xa0,
        0x85, 0x72, 0xc0, 0x07, 0x7a, 0xa8, 0x07, 0x79, 0x28, 0x07, 0x39, 0x20, 0x05, 0x3e, 0x30, 0x07, 0x76, 0x78, 0x87, 0x70, 0xa0, 0x07, 0x3f, 0xd0, 0x03, 0x3d, 0x68, 0x87, 0x74, 0x80, 0x87, 0x79,
        0xf8, 0x05, 0x7a, 0xc8, 0x07, 0x78, 0x28, 0x07, 0x14, 0x8c, 0x99, 0xac, 0x71, 0x60, 0x87, 0x70, 0x98, 0x87, 0x79, 0x70, 0x03, 0x5a, 0x28, 0x07, 0x7c, 0xa0, 0x87, 0x7a, 0x90, 0x87, 0x72, 0x90,
        0x03, 0x52, 0xe0, 0x03, 0x73, 0x60, 0x87, 0x77, 0x08, 0x07, 0x7a, 0xf0, 0x03, 0x24, 0x9c, 0x48, 0x72, 0x26, 0x6d, 0x1c, 0xd8, 0x21, 0x1c, 0xe6, 0x61, 0x1e, 0xdc, 0xc0, 0x14, 0xca, 0xa1, 0x1c,
        0xc8, 0x41, 0x1c, 0xc2, 0x61, 0x1c, 0xd6, 0x81, 0x16, 0xca, 0x01, 0x1f, 0xe8, 0xa1, 0x1e, 0xe4, 0xa1, 0x1c, 0xe4, 0x80, 0x14, 0xf8, 0x20, 0x0e, 0xfc, 0x00, 0x05, 0x83, 0xe8, 0x4c, 0xda, 0x38,
        0xb0, 0x43, 0x38, 0xcc, 0xc3, 0x3c, 0xb8, 0x81, 0x29, 0x94, 0x43, 0x39, 0x90, 0x83, 0x38, 0x84, 0xc3, 0x38, 0xac, 0x03, 0x2d, 0x94, 0x03, 0x3e, 0xd0, 0x43, 0x3d, 0xc8, 0x43, 0x39, 0xc8, 0x01,
        0x29, 0xf0, 0x01, 0x1c, 0xf8, 0x01, 0x0a, 0x06, 0xd9, 0x61, 0x04, 0xe1, 0x38, 0x82, 0x0b, 0xa8, 0x02, 0x0d, 0x18, 0x63, 0xca, 0x37, 0x49, 0x53, 0x44, 0x09, 0x93, 0xcf, 0x02, 0xcc, 0xb3, 0x10,
        0x11, 0x3b, 0x01, 0x13, 0x81, 0x82, 0x41, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50,
        0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78,
        0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07,
        0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0,
        0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x86, 0x3c, 0x08, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x16, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38,
        0x40, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x05, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47,
        0xc6, 0x04, 0x43, 0x1a, 0x25, 0x50, 0x0a, 0xe5, 0x50, 0x0c, 0x23, 0x00, 0x45, 0x50, 0x12, 0x25, 0x52, 0x30, 0x85, 0x40, 0x6d, 0x04, 0x80, 0xe6, 0x0c, 0x00, 0xd5, 0x19, 0x00, 0xba, 0x33, 0x00,
        0xa4, 0x67, 0x00, 0x88, 0xcf, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24,
        0xc6, 0xe5, 0xc6, 0x45, 0x46, 0x26, 0x46, 0xc6, 0x85, 0x06, 0x06, 0x04, 0xa5, 0x0c, 0x86, 0x66, 0xc6, 0x8c, 0x26, 0x2c, 0x46, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x06, 0x62, 0x82, 0x30, 0x14,
        0x1b, 0x84, 0x81, 0x98, 0x20, 0x0c, 0xc6, 0x06, 0x61, 0x30, 0x28, 0x8c, 0xcd, 0x4d, 0x10, 0x86, 0x63, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x61, 0x40, 0x26, 0x08, 0xd3, 0x43, 0x60, 0x82, 0x30, 0x24,
        0x13, 0x84, 0x41, 0xd9, 0x20, 0x2c, 0xcf, 0x86, 0x64, 0x61, 0x9a, 0x65, 0x19, 0x9c, 0x05, 0xda, 0x10, 0x44, 0x13, 0x84, 0x0a, 0x9a, 0x20, 0x0c, 0xcb, 0x04, 0xa1, 0x71, 0x36, 0x08, 0xce, 0xb0,
        0x61, 0x59, 0xa6, 0x66, 0x59, 0x06, 0xaa, 0xaa, 0x2a, 0x6b, 0x82, 0x70, 0x45, 0x1b, 0x04, 0x67, 0xd9, 0xb0, 0x0c, 0x58, 0xb3, 0x0c, 0x03, 0x55, 0x55, 0x55, 0xb6, 0x41, 0xb8, 0xb4, 0x09, 0x82,
        0x26, 0x4d, 0x10, 0x06, 0x66, 0x03, 0xb2, 0x70, 0xcd, 0xb2, 0x0c, 0x1d, 0xb0, 0x21, 0xf0, 0x26, 0x08, 0xdc, 0xb4, 0x01, 0x59, 0xc0, 0xa0, 0x59, 0x96, 0x61, 0x01, 0x36, 0x04, 0x61, 0xb0, 0x81,
        0x90, 0xb6, 0x4f, 0x0c, 0x26, 0x08, 0x02, 0x40, 0xa2, 0x2d, 0x2c, 0xcd, 0x6d, 0x82, 0x30, 0x34, 0x1b, 0x86, 0x61, 0x18, 0x36, 0x08, 0x66, 0x70, 0x06, 0x1b, 0x0a, 0x32, 0x28, 0x03, 0x60, 0x0c,
        0xd0, 0xa0, 0x0a, 0x1b, 0x9b, 0x5d, 0x9b, 0x4b, 0x1a, 0x59, 0x99, 0x1b, 0xdd, 0x94, 0x20, 0xa8, 0x42, 0x86, 0xe7, 0x62, 0x57, 0x26, 0x37, 0x97, 0xf6, 0xe6, 0x36, 0x25, 0x20, 0x9a, 0x90, 0xe1,
        0xb9, 0xd8, 0x85, 0xb1, 0xd9, 0x95, 0xc9, 0x4d, 0x09, 0x8c, 0x3a, 0x64, 0x78, 0x2e, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x82, 0xa4, 0x0c, 0x19, 0x9e, 0x8b,
        0x5c, 0xd9, 0xdc, 0x5b, 0x9d, 0xdc, 0x58, 0xd9, 0xdc, 0x94, 0x40, 0x0c, 0xea, 0x90, 0xe1, 0xb9, 0x94, 0xb9, 0xd1, 0xc9, 0xe5, 0x41, 0xbd, 0xa5, 0xb9, 0xd1, 0xcd, 0x4d, 0x09, 0xd0, 0x00, 0x00,
        0x79, 0x18, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73,
        0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b,
        0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20,
        0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61,
        0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87,
        0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98,
        0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61,
        0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b,
        0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60,
        0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x26, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, 0x41, 0x44,
        0xa5, 0x03, 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, 0x6d, 0x03, 0xd2, 0x70, 0xf9, 0xce, 0xe3, 0x0b, 0x11, 0x01, 0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, 0x58, 0x80, 0x37, 0x5c, 0xbe, 0xf3,
        0xf8, 0x56, 0x84, 0x4c, 0x04, 0x0b, 0x30, 0xcf, 0x42, 0x44, 0x1f, 0x41, 0x0c, 0x01, 0x20, 0x28, 0x60, 0x04, 0x0c, 0x06, 0x40, 0x30, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00,
        0x37, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x4a, 0xae, 0xec, 0x4a, 0x5c, 0x80, 0x48, 0x09, 0x8c, 0x00, 0x94, 0x41, 0x11, 0xd0, 0x99,
        0x01, 0x00, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0xe0, 0x64, 0x48, 0x81, 0x61, 0xce, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x38, 0x5a, 0x62, 0x54, 0xd5, 0x33, 0x62, 0x90, 0x00, 0x20,
        0x08, 0x06, 0xce, 0xa6, 0x18, 0x96, 0x05, 0x8d, 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0xc3, 0x2d, 0xc6, 0x75, 0x45, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0xe0, 0x74, 0x8c, 0x81, 0x61, 0xd2, 0x88,
        0xc1, 0x01, 0x80, 0x20, 0x18, 0x2c, 0x1f, 0x13, 0x74, 0xa3, 0x09, 0x01, 0x30, 0x9a, 0x20, 0x04, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xb0, 0x88, 0xc1, 0x43, 0x70, 0xa3, 0x09, 0x81, 0x30, 0x9a,
        0x20, 0x0c, 0xa3, 0x09, 0x03, 0x30, 0x9a, 0x40, 0x04, 0x23, 0x06, 0x13, 0x00, 0x82, 0x60, 0x80, 0xa0, 0xc1, 0xc4, 0x2c, 0x8a, 0x10, 0x38, 0x0e, 0x31, 0x38, 0x87, 0xe1, 0x38, 0x23, 0x06, 0x07,
        0x00, 0x82, 0x60, 0xb0, 0x9c, 0x01, 0x95, 0x94, 0xc1, 0x68, 0x42, 0x00, 0x8c, 0x26, 0x08, 0xc1, 0x88, 0xc1, 0x01, 0x80, 0x20, 0x18, 0x2c, 0x6a, 0x70, 0x31, 0x64, 0x30, 0x9a, 0x10, 0x08, 0xa3,
        0x09, 0xc2, 0x30, 0x9a, 0x30, 0x00, 0xa3, 0x09, 0x44, 0x30, 0x62, 0x30, 0x01, 0x20, 0x08, 0x06, 0x08, 0x1c, 0x6c, 0xd5, 0x24, 0x09, 0x81, 0x65, 0x11, 0x83, 0x75, 0x18, 0x96, 0x85, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
    };
    static const D3D12_SHADER_BYTECODE cs_code_dxil = SHADER_BYTECODE(cs_code);

#define TEX_WIDTH 16
#define TEX_HEIGHT 16
#define MIP_REGION_WIDTH 4
#define MIP_REGION_HEIGHT 4
#define FEEDBACK_WIDTH (TEX_WIDTH / MIP_REGION_WIDTH)
#define FEEDBACK_HEIGHT (TEX_HEIGHT / MIP_REGION_HEIGHT)
#define TEX_MIP_LEVELS 2

    /* Level 0 has 4x4 regions.
     * Level 1 has 2x2 regions. Minimum viable size to test overlapping tile access. */

    /* These reference results are based on AMD output. NV outputs are borderline non-sensical for purposes of testing implementation. */
    static const struct test
    {
        /* If sub-texel offset is 0, we intend to sample exactly at texel center. */
#define MAKE_TEXEL(x, y, sub_x, sub_y) { ((float)(x) + 0.5f + (float)(sub_x) / 256.0f) / TEX_WIDTH, ((float)(y) + 0.5f + (float)(sub_y) / 256.0f) / TEX_HEIGHT }
#define MAKE_MASK0(row0, row1, row2, row3) (((row0) << 0) | ((row1) << 4) | ((row2) << 8) | ((row3) << 12))
#define MAKE_MASK1(row0, row1) (((row0) << 0) | ((row1) << 2))
#define MAKE_ROW0(a, b, c, d) (((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3))
#define MAKE_ROW1(a, b) (((a) << 0) | ((b) << 1))
#define E 0xff
#define ER {E, E, E, E}

        float texel[2];
        float dx[2];
        float dy[2];

        uint32_t mask0; /* Bitmask of accessed regions in level 0. */
        uint32_t mask1; /* And level 1 */
        uint8_t min_level[FEEDBACK_HEIGHT][FEEDBACK_WIDTH];

        D3D12_TEXTURE_ADDRESS_MODE wrap_u, wrap_v;
        D3D12_FILTER filter;
        UINT max_aniso;
        float mip_bias;
        float min_lod;
        float max_lod;
    } tests[] = {
        /* Very basic point sampling test just to sanity check. */
        {
            MAKE_TEXEL(4, 4, 0, 0), { 0, 0 }, { 0, 0 },
            MAKE_MASK0(0, MAKE_ROW0(0, 1, 0, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {ER, { E, 0, E, E }, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_MIP_POINT,
        },

        /* Proves that sampler filtering mode is important and accounted for. */
        {
            MAKE_TEXEL(4, 4, 0, 0), { 0, 0 }, { 0, 0 },
            MAKE_MASK0(MAKE_ROW0(1, 1, 0, 0), MAKE_ROW0(1, 1, 0, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {{0, 0, E, E}, {0, 0, E, E}, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_MIP_LINEAR,
            0, 0.0f,
        },
        {
            MAKE_TEXEL(4, 4, 0, 0), { 1.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT }, /* Compute exactly LOD 0 */
            MAKE_MASK0(0, MAKE_ROW0(0, 1, 0, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {ER, { E, 0, E, E }, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT,
            0, 0.0f, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(4, 4, 0, 0), { 1.1f / TEX_WIDTH, 0 }, { 0, 1.1f / TEX_HEIGHT }, /* Compute LOD slightly above 0 to trigger MIN filter. */
            MAKE_MASK0(MAKE_ROW0(1, 1, 0, 0), MAKE_ROW0(1, 1, 0, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {{0, 0, E, E}, {0, 0, E, E}, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT,
            0, 0.0f, 0.0f, 1.0f,
        },
        /* Check if mip-bias is accounted for. */
        {
            MAKE_TEXEL(4, 4, 0, 0), { 1.1f / TEX_WIDTH, 0 }, { 0, 1.1f / TEX_HEIGHT },
            MAKE_MASK0(0, MAKE_ROW0(0, 1, 0, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {ER, { E, 0, E, E }, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT,
            0, -0.5f, 0.0f, 1.0f,
        },
        /* Test if mip clamp is accounted for (minLOD) */
        {
            MAKE_TEXEL(4, 4, 0, 0), { 0 }, { 0 },
            MAKE_MASK0(MAKE_ROW0(1, 1, 0, 0), MAKE_ROW0(1, 1, 0, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {{0, 0, E, E}, {0, 0, E, E}, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT,
            0, 0.0f, 0.1f, 1.0f,
        },
        /* Test if mip clamp is accounted for (maxLOD) */
        {
            MAKE_TEXEL(4, 4, 0, 0), { 1.1f / TEX_WIDTH, 0 }, { 0, 1.1f / TEX_HEIGHT }, /* Compute LOD slightly above 0 to trigger MIN filter. */
            MAKE_MASK0(0, MAKE_ROW0(0, 1, 0, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {ER, { E, 0, E, E }, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT,
            0, 0.0f, 0.0f, 0.0f,
        },
        /* Test POINT mip filtering. floor(lod + 0.5) behavior. */
        {
            MAKE_TEXEL(8, 8, 0, 0), { 1.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, 0, MAKE_ROW0(0, 0, 1, 0), 0),
            MAKE_MASK1(0, 0),
            {ER, ER, { E, E, 0, E }, ER },
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_MIP_POINT,
            0, 0.49f, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(8, 8, 0, 0), { 1.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, 0, 0, 0),
            MAKE_MASK1(0, MAKE_ROW1(0, 1)),
            {ER, ER, {E, E, 0, E}, ER}, /* ?!?!?! It's only accessing LOD 1, but it's marking LOD 0 as minimum ;_; */
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_MIP_POINT,
            0, 0.5f, 0.0f, 1.0f,
        },

        /* Test LINEAR mip filtering. */
        {
            MAKE_TEXEL(8, 8, 0, 0), { 1.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, 0, MAKE_ROW0(0, 0, 1, 0), 0),
            MAKE_MASK1(0, 0),
            {ER, ER, {E, E, 0, E}, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR,
            0, 0.0f, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(8, 8, 0, 0), { 1.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, 0, MAKE_ROW0(0, 0, 1, 0), 0),
            MAKE_MASK1(0, 0),
            {ER, ER, {E, E, 0, E}, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR,
            0, 0.25f / 256.0f /* mip filter is fixed point */, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(8, 8, 0, 0), { 1.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, 0, MAKE_ROW0(0, 0, 1, 0), 0),
            MAKE_MASK1(0, 0),
            {ER, ER, {E, E, 0, E}, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR,
            0, 0.5f / 256.0f /* mip filter is fixed point */, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(8, 8, 0, 0), { 1.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, 0, MAKE_ROW0(0, 0, 1, 0), 0),
            MAKE_MASK1(0, MAKE_ROW1(0, 1)),
            {ER, ER, {E, E, 0, E}, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR,
            0, 1.0f / 256.0f /* mip filter is fixed point */, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(8, 8, 0, 0), { 1.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, 0, MAKE_ROW0(0, 0, 1, 0), 0),
            MAKE_MASK1(0, MAKE_ROW1(0, 1)),
            {ER, ER, {E, E, 0, E}, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR,
            0, 255.0f / 256.0f /* mip filter is fixed point */, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(8, 8, 0, 0), { 1.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, 0, MAKE_ROW0(0, 0, 1, 0), 0),
            MAKE_MASK1(0, MAKE_ROW1(0, 1)),
            {ER, ER, {E, E, 0, E}, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR,
            0, 255.5f / 256.0f /* mip filter is fixed point */, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(8, 8, 0, 0), { 1.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, 0, MAKE_ROW0(0, 0, 1, 0), 0),
            MAKE_MASK1(0, MAKE_ROW1(0, 1)),
            {ER, ER, {E, E, 0, E}, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR,
            0, 255.9f / 256.0f /* level is truncated before fixed point snap? */, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(8, 8, 0, 0), { 1.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, 0, 0, 0),
            MAKE_MASK1(0, MAKE_ROW1(0, 1)),
            {ER, ER, {E, E, 1, E}, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR,
            0, 1.0f /* mip filter is fixed point */, 0.0f, 1.0f,
        },
        /* Try to sample in the center of a mip region (texel 5.5). Guess what happens next!
         * Observed behavior is that when very close to the center of a mip region, no neighbors are affected.
         * Straying just a little bit from the center will touch the closest neighbor.
         * Theory: sampling coordinate is converted to a fixed-point texel value in feedback space.
         * A [coord - e, coord + e] box is spanned out to determine writes, where e is likely 0.5 - epsilon. */
        {
            MAKE_TEXEL(5, 5, 125, 125), { 0, 0 }, { 0, 0 },
            MAKE_MASK0(MAKE_ROW0(1, 1, 0, 0), MAKE_ROW0(1, 1, 0, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {{0, 0, E, E}, {0, 0, E, E}, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_MIP_LINEAR,
            0, 0.0f,
        },
        {
            MAKE_TEXEL(5, 5, 126, 126), { 0, 0 }, { 0, 0 },
            MAKE_MASK0(0, MAKE_ROW0(0, 1, 0, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {ER, {E, 0, E, E}, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_MIP_LINEAR,
            0, 0.0f,
        },
        {
            MAKE_TEXEL(6, 6, -126, -126), { 0, 0 }, { 0, 0 },
            MAKE_MASK0(0, MAKE_ROW0(0, 1, 0, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {ER, {E, 0, E, E}, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_MIP_LINEAR,
            0, 0.0f,
        },
        {
            MAKE_TEXEL(6, 6, -125, -125), { 0, 0 }, { 0, 0 },
            MAKE_MASK0(0, MAKE_ROW0(0, 1, 1, 0), MAKE_ROW0(0, 1, 1, 0), 0),
            MAKE_MASK1(0, 0),
            {ER, {E, 0, 0, E}, {E, 0, 0, E}, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_MIN_MAG_MIP_LINEAR,
            0, 0.0f,
        },
        /* Try anisotropic. Study if we can observe a rectangular footprint (we do). */
        {
            MAKE_TEXEL(5, 5, 128, 128), { 2.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, MAKE_ROW0(1, 1, 1, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {ER, {0, 0, 0, E}, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_ANISOTROPIC,
            2, 0.0f, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(5, 5, 128, 128), { 4.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT }, /* If we go beyond MaxAniso, we go to lower mips. */
            MAKE_MASK0(0, 0, 0, 0),
            MAKE_MASK1(MAKE_ROW1(1, 1), MAKE_ROW1(1, 1)),
            {ER, {1, 1, 1, E}, ER, ER}, /* Interesting behavior! */
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_ANISOTROPIC,
            2, 0.0f, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(5, 5, 128, 128), { 4.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, MAKE_ROW0(1, 1, 1, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {ER, {0, 0, 0, E}, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_ANISOTROPIC,
            4, 0.0f, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(5, 5, 128, 128), { 8.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, MAKE_ROW0(1, 1, 1, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {ER, {0, 0, 0, E}, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_ANISOTROPIC,
            8, 0.0f, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(6, 5, 2, 128), { 8.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT },
            MAKE_MASK0(0, MAKE_ROW0(1, 1, 1, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {ER, {0, 0, 0, E}, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_ANISOTROPIC,
            8, 0.0f, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(6, 5, 3, 128), { 8.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT }, /* Observe threshold for where 8x aniso starts to light up the right-most tile. */
            MAKE_MASK0(0, MAKE_ROW0(1, 1, 1, 1), 0, 0),
            MAKE_MASK1(0, 0),
            {ER, {0, 0, 0, 0}, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_ANISOTROPIC,
            8, 0.0f, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(5, 5, 128, 128), { 8.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT }, /* Effective aniso rate does matter! (>_<) */
            MAKE_MASK0(0, MAKE_ROW0(1, 1, 1, 0), 0, 0),
            MAKE_MASK1(0, 0),
            {ER, {0, 0, 0, E}, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_ANISOTROPIC,
            16, 0.0f, 0.0f, 1.0f,
        },
        {
            MAKE_TEXEL(5, 5, 128, 128), { 16.0f / TEX_WIDTH, 0 }, { 0, 1.0f / TEX_HEIGHT }, /* Aniso rate does matter! (>_<) */
            MAKE_MASK0(0, MAKE_ROW0(1, 1, 1, 1), 0, 0),
            MAKE_MASK1(0, 0),
            {ER, {0, 0, 0, 0}, ER, ER},
            D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_FILTER_ANISOTROPIC,
            16, 0.0f, 0.0f, 1.0f,
        },
    };
#undef MAKE_TEXEL
#undef MAKE_MASK0
#undef MAKE_MASK1
#undef MAKE_ROW0
#undef MAKE_ROW1
#undef E
#undef ER

    memset(&context_desc, 0, sizeof(context_desc));
    context_desc.no_pipeline = true;
    context_desc.no_render_target = true;
    context_desc.no_root_signature = true;
    if (!init_test_context(&context, &context_desc))
        return;

    if (FAILED(ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS7, &features7, sizeof(features7))) ||
            features7.SamplerFeedbackTier < D3D12_SAMPLER_FEEDBACK_TIER_0_9)
    {
        skip("Sampler feedback not supported.\n");
        destroy_test_context(&context);
        return;
    }

    hr = ID3D12Device_QueryInterface(context.device, &IID_ID3D12Device8, (void **)&device8);
    ok(SUCCEEDED(hr), "Failed to query Device8, hr #%x.\n", hr);
    hr = ID3D12GraphicsCommandList_QueryInterface(context.list, &IID_ID3D12GraphicsCommandList1, (void **)&list1);
    ok(SUCCEEDED(hr), "Failed to query GraphicsCommandList1, hr #%x.\n", hr);

    memset(&rs_desc, 0, sizeof(rs_desc));
    memset(desc_range, 0, sizeof(desc_range));
    memset(&desc_range_sampler, 0, sizeof(desc_range_sampler));
    memset(rs_param, 0, sizeof(rs_param));
    rs_desc.NumParameters = ARRAY_SIZE(rs_param);
    rs_desc.pParameters = rs_param;

    rs_param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
    rs_param[0].DescriptorTable.NumDescriptorRanges = ARRAY_SIZE(desc_range);
    rs_param[0].DescriptorTable.pDescriptorRanges = desc_range;
    desc_range[0].NumDescriptors = 2;
    desc_range[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
    desc_range[1].NumDescriptors = 1;
    desc_range[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
    desc_range[1].OffsetInDescriptorsFromTableStart = 2;
    rs_param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
    rs_param[1].Constants.Num32BitValues = 6;
    rs_param[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
    rs_param[2].DescriptorTable.NumDescriptorRanges = 1;
    rs_param[2].DescriptorTable.pDescriptorRanges = &desc_range_sampler;
    desc_range_sampler.NumDescriptors = 1;
    desc_range_sampler.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;

    create_root_signature(context.device, &rs_desc, &context.root_signature);
    context.pipeline_state = create_compute_pipeline_state(context.device, context.root_signature, cs_code_dxil);
    ok(!!context.pipeline_state, "Failed to create PSO.\n");

    desc_heaps[0] = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 3);
    desc_heaps[1] = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 1);
    desc_heap_cpu = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2);

    resource = create_default_texture2d(context.device, TEX_WIDTH, TEX_HEIGHT, 1, TEX_MIP_LEVELS, DXGI_FORMAT_R8_UNORM, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
    resolve_used = create_default_texture2d(context.device, FEEDBACK_WIDTH, FEEDBACK_HEIGHT, 1, TEX_MIP_LEVELS, DXGI_FORMAT_R8_UINT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_SOURCE);
    resolve_min = create_default_texture2d(context.device, FEEDBACK_WIDTH, FEEDBACK_HEIGHT, 1, 1, DXGI_FORMAT_R8_UINT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_SOURCE);

    memset(&desc, 0, sizeof(desc));
    memset(&heap_props, 0, sizeof(heap_props));

    heap_props.Type = D3D12_HEAP_TYPE_DEFAULT;
    desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    desc.SampleDesc.Count = 1;
    desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
    desc.Width = TEX_WIDTH;
    desc.Height = TEX_HEIGHT;
    desc.DepthOrArraySize = 1;
    desc.MipLevels = TEX_MIP_LEVELS;
    desc.SamplerFeedbackMipRegion.Width = MIP_REGION_WIDTH;
    desc.SamplerFeedbackMipRegion.Height = MIP_REGION_HEIGHT;
    desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
    desc.Format = DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE;
    hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, &desc, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, NULL, NULL, &IID_ID3D12Resource, (void **)&feedback_used);
    ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);
    desc.Format = DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE;
    hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, &desc, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, NULL, NULL, &IID_ID3D12Resource, (void **)&feedback_min);
    ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);

    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback_used, get_cpu_descriptor_handle(&context, desc_heaps[0], 0));
    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback_used, get_cpu_descriptor_handle(&context, desc_heap_cpu, 0));
    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback_min, get_cpu_descriptor_handle(&context, desc_heaps[0], 1));
    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback_min, get_cpu_descriptor_handle(&context, desc_heap_cpu, 1));

    {
        D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc;
        memset(&srv_desc, 0, sizeof(srv_desc));
        srv_desc.Format = DXGI_FORMAT_R8_UNORM;
        srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
        srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
        srv_desc.Texture2D.MipLevels = TEX_MIP_LEVELS; /* Verify that the SRV itself clamps the feedback that is written. */
        ID3D12Device_CreateShaderResourceView(context.device, resource, &srv_desc, get_cpu_descriptor_handle(&context, desc_heaps[0], 2));
    }

    for (i = 0; i < ARRAY_SIZE(tests); i++)
    {
        D3D12_SAMPLER_DESC sampler_desc;
        uint32_t value_mask;

        vkd3d_test_set_context("Test %u", i);

        memset(&sampler_desc, 0, sizeof(sampler_desc));
        sampler_desc.AddressU = tests[i].wrap_u;
        sampler_desc.AddressV = tests[i].wrap_v;
        sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
        sampler_desc.Filter = tests[i].filter;
        sampler_desc.MinLOD = tests[i].min_lod;
        sampler_desc.MaxLOD = tests[i].max_lod;
        sampler_desc.MaxAnisotropy = tests[i].max_aniso;
        sampler_desc.MipLODBias = tests[i].mip_bias;
        ID3D12Device_CreateSampler(context.device, &sampler_desc, ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heaps[1]));

        ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, ARRAY_SIZE(desc_heaps), desc_heaps);
        transition_resource_state(context.list, feedback_used, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
        transition_resource_state(context.list, feedback_min, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);

        {
            UINT zeroes[4] = { 0x80 }; /* Clear value is ignored. The actual clear value is opaque, but after a resolve, it should be 0. */
            ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(context.list,
                get_gpu_descriptor_handle(&context, desc_heaps[0], 0),
                get_cpu_descriptor_handle(&context, desc_heap_cpu, 0),
                feedback_used, zeroes, 0, NULL);
            ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(context.list,
                get_gpu_descriptor_handle(&context, desc_heaps[0], 1),
                get_cpu_descriptor_handle(&context, desc_heap_cpu, 1),
                feedback_min, zeroes, 0, NULL);
            uav_barrier(context.list, feedback_used);
            uav_barrier(context.list, feedback_min);
        }

        ID3D12GraphicsCommandList_SetComputeRootSignature(context.list, context.root_signature);
        ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state);
        ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 0, ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heaps[0]));
        ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(context.list, 2, ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heaps[1]));

        ID3D12GraphicsCommandList_SetComputeRoot32BitConstants(context.list, 1, 6, &tests[i], 0);
        ID3D12GraphicsCommandList_Dispatch(context.list, 1, 1, 1);

        transition_resource_state(context.list, feedback_used, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
        transition_resource_state(context.list, resolve_used, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RESOLVE_DEST);
        transition_resource_state(context.list, feedback_min, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
        transition_resource_state(context.list, resolve_min, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RESOLVE_DEST);
        ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve_used, UINT_MAX, 0, 0, feedback_used, UINT_MAX, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
        ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve_min, UINT_MAX, 0, 0, feedback_min, UINT_MAX, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
        transition_resource_state(context.list, resolve_used, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
        transition_resource_state(context.list, resolve_min, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);

        /* This test is extremely hard to pass, and is left as an exploratory test for now.
         * Results vary wildly between all vendors here. */
        value_mask = 0;
        get_texture_readback_with_command_list(resolve_used, 0, &rb, context.queue, context.list);
        for (y = 0; y < FEEDBACK_WIDTH; y++)
        {
            for (x = 0; x < FEEDBACK_WIDTH; x++)
            {
                uint8_t value = get_readback_uint8(&rb, x, y);
                if (is_amd_windows_device(context.device))
                    ok(value == 0 || value == 0xff, "Unexpected boolean %u.\n", value);
                if (value)
                    value_mask |= 1u << (y * FEEDBACK_WIDTH + x);
            }
        }

        if (is_amd_windows_device(context.device))
            ok(value_mask == tests[i].mask0, "Mip0: Expected #%x, got #%x.\n", tests[i].mask0, value_mask);
        release_resource_readback(&rb);
        reset_command_list(context.list, context.allocator);

        value_mask = 0;
        get_texture_readback_with_command_list(resolve_used, 1, &rb, context.queue, context.list);
        for (y = 0; y < FEEDBACK_WIDTH / 2; y++)
        {
            for (x = 0; x < FEEDBACK_WIDTH / 2; x++)
            {
                uint8_t value = get_readback_uint8(&rb, x, y);
                if (is_amd_windows_device(context.device))
                    ok(value == 0 || value == 0xff, "Unexpected boolean %u.\n", value);
                if (value)
                    value_mask |= 1u << (y * FEEDBACK_WIDTH / 2 + x);
            }
        }
        if (is_amd_windows_device(context.device))
            ok(value_mask == tests[i].mask1, "Mip1: Expected #%x, got #%x.\n", tests[i].mask1, value_mask);
        release_resource_readback(&rb);
        reset_command_list(context.list, context.allocator);

        get_texture_readback_with_command_list(resolve_min, 0, &rb, context.queue, context.list);
        for (y = 0; y < FEEDBACK_WIDTH; y++)
        {
            for (x = 0; x < FEEDBACK_WIDTH; x++)
            {
                uint8_t value = get_readback_uint8(&rb, x, y);
                if (is_amd_windows_device(context.device))
                    ok(value == tests[i].min_level[y][x], "MinLevel %u, %u: expected %u, got %u.\n", x, y, tests[i].min_level[y][x], value);
            }
        }
        if (!is_amd_windows_device(context.device))
            skip("Skipping exploratory test on anything other than AMD Windows.\n");
        release_resource_readback(&rb);
        reset_command_list(context.list, context.allocator);
    }
    vkd3d_test_set_context(NULL);

    ID3D12GraphicsCommandList1_Release(list1);
    ID3D12Resource_Release(resource);
    ID3D12Resource_Release(feedback_used);
    ID3D12Resource_Release(resolve_used);
    ID3D12Resource_Release(feedback_min);
    ID3D12Resource_Release(resolve_min);
    for (i = 0; i < ARRAY_SIZE(desc_heaps); i++)
        ID3D12DescriptorHeap_Release(desc_heaps[i]);
    ID3D12DescriptorHeap_Release(desc_heap_cpu);
    ID3D12Device8_Release(device8);
    destroy_test_context(&context);
#undef TEX_WIDTH
#undef TEX_HEIGHT
#undef MIP_REGION_WIDTH
#undef MIP_REGION_HEIGHT
#undef FEEDBACK_WIDTH
#undef FEEDBACK_HEIGHT
#undef TEX_MIP_LEVELS
}

static void test_sampler_feedback_implicit_lod_inner(bool biased)
{
    D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
    D3D12_FEATURE_DATA_D3D12_OPTIONS7 features7;
    D3D12_STATIC_SAMPLER_DESC static_sampler;
    struct test_context_desc context_desc;
    D3D12_DESCRIPTOR_RANGE desc_range[2];
    ID3D12DescriptorHeap *desc_heap_cpu;
    D3D12_ROOT_SIGNATURE_DESC rs_desc;
    ID3D12GraphicsCommandList1 *list1;
    D3D12_ROOT_PARAMETER rs_param[2];
    D3D12_HEAP_PROPERTIES heap_props;
    ID3D12DescriptorHeap *desc_heap;
    struct test_context context;
    struct resource_readback rb;
    D3D12_RESOURCE_DESC1 desc;
    ID3D12Resource *resource;
    ID3D12Resource *feedback;
    ID3D12Resource *resolve;
    ID3D12Device8 *device8;
    unsigned int x, y, i;
    D3D12_VIEWPORT vp;
    D3D12_RECT sci;
    HRESULT hr;

    static const BYTE vs_code[] =
    {
#if 0
    float4 main(uint vid : SV_VertexID) : SV_Position
    {
            float4 pos;
            pos.x = -1.0 + 4.0 * (vid & 1);
            pos.y = -1.0 + 2.0 * (vid & 2);
            pos.z = 0.0;
            pos.w = 1.0;
            return pos;
    }
#endif
        0x44, 0x58, 0x42, 0x43, 0x82, 0xce, 0x0f, 0x3e, 0xe9, 0x14, 0x2e, 0xc7, 0xf8, 0x6e, 0xff, 0x4a, 0xb6, 0x6e, 0x4c, 0x87, 0x01, 0x00, 0x00, 0x00, 0x64, 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
        0x38, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x56, 0x65, 0x72, 0x74, 0x65,
        0x78, 0x49, 0x44, 0x00, 0x4f, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00,
        0x50, 0x53, 0x56, 0x30, 0x7c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x01,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, 0x03, 0x04, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0xf5, 0xdf, 0x57, 0x2b, 0x70, 0xd0, 0xf3, 0xed, 0x3a, 0xb1, 0x5e, 0x7a, 0xba, 0x23, 0x26,
        0x44, 0x58, 0x49, 0x4c, 0xfc, 0x04, 0x00, 0x00, 0x66, 0x00, 0x01, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x06, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xe4, 0x04, 0x00, 0x00,
        0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49,
        0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b,
        0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a,
        0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20,
        0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09,
        0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x30, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x39,
        0x02, 0x30, 0x98, 0x23, 0x40, 0x8a, 0x31, 0x33, 0x43, 0x43, 0x35, 0x03, 0x50, 0x0c, 0x98, 0x19, 0x3a, 0xc2, 0x81, 0x80, 0x1c, 0x18, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87,
        0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d,
        0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07,
        0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20,
        0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76,
        0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x05, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20,
        0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x9a,
        0x12, 0x28, 0x86, 0x72, 0x18, 0x01, 0x28, 0x83, 0xf2, 0x20, 0x2a, 0x85, 0x12, 0x18, 0x01, 0x28, 0x89, 0x32, 0x28, 0x04, 0xda, 0xb1, 0x86, 0x80, 0x18, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00,
        0x46, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0xe5, 0xc6, 0x45, 0x46, 0x26, 0x46, 0xc6, 0x85, 0x06, 0x06, 0x04,
        0xa5, 0x0c, 0x86, 0x66, 0xc6, 0x8c, 0x26, 0x2c, 0x46, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x86, 0x61, 0x82, 0x30, 0x10, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x0c, 0xc5, 0x06, 0x61, 0x30, 0x28, 0xd8,
        0xcd, 0x6d, 0x18, 0x10, 0x82, 0x98, 0x20, 0x2c, 0xcf, 0x86, 0x40, 0x99, 0x20, 0x08, 0x00, 0x0f, 0xbb, 0xb9, 0xaf, 0xb6, 0xb0, 0x34, 0xb7, 0x09, 0xc2, 0x60, 0x70, 0x99, 0xb2, 0xfa, 0xb2, 0x2a,
        0x93, 0xa3, 0x2b, 0xc3, 0x4b, 0x22, 0x9a, 0x20, 0x10, 0xc9, 0x04, 0x81, 0x50, 0x36, 0x04, 0xce, 0x04, 0x81, 0x58, 0x26, 0x08, 0xc3, 0xb1, 0x41, 0xa0, 0x86, 0x0d, 0x8b, 0xf3, 0x40, 0x91, 0x34,
        0x0d, 0x91, 0x33, 0x55, 0x1b, 0x02, 0x8b, 0xcb, 0x94, 0xd5, 0x17, 0xd4, 0xdb, 0x5c, 0x1a, 0x5d, 0xda, 0x9b, 0xdb, 0x04, 0x81, 0x60, 0x26, 0x08, 0x44, 0x33, 0x41, 0x20, 0x9c, 0x09, 0xc2, 0x80,
        0x6c, 0x10, 0x28, 0x6e, 0xc3, 0xe2, 0x60, 0x99, 0x26, 0x6d, 0xc3, 0xe6, 0x4c, 0xdd, 0x86, 0xc0, 0xdb, 0x30, 0x5c, 0x1f, 0xb0, 0xa1, 0x60, 0x1a, 0x30, 0x00, 0x80, 0x2a, 0x6c, 0x6c, 0x76, 0x6d,
        0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x82, 0xa0, 0x0a, 0x19, 0x9e, 0x8b, 0x5d, 0x99, 0xdc, 0x5c, 0xda, 0x9b, 0xdb, 0x94, 0x80, 0x68, 0x42, 0x86, 0xe7, 0x62, 0x17, 0xc6, 0x66, 0x57, 0x26,
        0x37, 0x25, 0x30, 0xea, 0x90, 0xe1, 0xb9, 0xcc, 0xa1, 0x85, 0x91, 0x95, 0xc9, 0x35, 0xbd, 0x91, 0x95, 0xb1, 0x4d, 0x09, 0x90, 0x3a, 0x64, 0x78, 0x2e, 0x76, 0x69, 0x65, 0x77, 0x49, 0x64, 0x53,
        0x74, 0x61, 0x74, 0x65, 0x53, 0x02, 0xa5, 0x0e, 0x19, 0x9e, 0x4b, 0x99, 0x1b, 0x9d, 0x5c, 0x1e, 0xd4, 0x5b, 0x9a, 0x1b, 0xdd, 0xdc, 0x94, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00,
        0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6,
        0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8,
        0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11,
        0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89,
        0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37,
        0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81,
        0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c,
        0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc,
        0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, 0xe0, 0x06, 0xe4, 0x20,
        0x0e, 0xe7, 0xe0, 0x06, 0xf6, 0x10, 0x0e, 0xf2, 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x16, 0x30, 0x0d, 0x97,
        0xef, 0x3c, 0xfe, 0xe2, 0x00, 0x83, 0xd8, 0x3c, 0xd4, 0xe4, 0x23, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00,
        0x47, 0x25, 0xfd, 0x0c, 0x80, 0x34, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x34, 0xa5, 0x50, 0x08,
        0x33, 0x00, 0x45, 0x40, 0x54, 0x04, 0x74, 0x63, 0x04, 0x20, 0x08, 0x82, 0xf8, 0x2f, 0x8c, 0x11, 0x80, 0x20, 0x08, 0xa2, 0x60, 0x30, 0x46, 0x00, 0x82, 0x20, 0x08, 0x82, 0xc1, 0x08, 0xc0, 0x18,
        0x01, 0x08, 0x82, 0x20, 0xfe, 0x01, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x50, 0x64, 0x09, 0x45, 0x3d, 0x48, 0x05, 0x98, 0x5e, 0x70, 0x65, 0xc1, 0x21, 0x1f, 0x0b, 0x12, 0xf8, 0x54,
        0xc1, 0xe8, 0x05, 0x57, 0x16, 0x28, 0xf2, 0xb1, 0xa0, 0x81, 0xcf, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x61, 0x30, 0x75, 0x1d, 0x56, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x12, 0x06,
        0x53, 0xd7, 0x65, 0xc1, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x61, 0x30, 0x75, 0xdd, 0xb3, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x12, 0x06, 0x53, 0xd7, 0x59, 0x0a, 0x02, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
    };
    static const D3D12_SHADER_BYTECODE vs_code_dxil = SHADER_BYTECODE(vs_code);

    /* DXC bans compute shader derivatives + implicit LOD feedback, so have to use PS path ... */

    static const BYTE ps_code_non_bias[] =
    {
#if 0
    Texture2D<float> T : register(t0);
    SamplerState S : register(s0);
    FeedbackTexture2D<SAMPLER_FEEDBACK_MIN_MIP> FB : register(u0);

    cbuffer Cbuf : register(b0) { float2 uv; float grad; float bias; };

    void main(float4 pos : SV_Position)
    {
            int2 ipos = int2(pos.xy);
            float2 modified_uv = uv;
            modified_uv.x += float(ipos.x) * grad;
            modified_uv.y += float(ipos.y) * grad;

            FB.WriteSamplerFeedback(T, S, modified_uv);
    }
#endif
        0x44, 0x58, 0x42, 0x43, 0xe4, 0xac, 0x93, 0x4b, 0x23, 0x7e, 0xa7, 0x72, 0x9f, 0xbf, 0x07, 0xe6, 0x3d, 0x28, 0x28, 0x62, 0x01, 0x00, 0x00, 0x00, 0xdc, 0x08, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
        0x38, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74,
        0x69, 0x6f, 0x6e, 0x00, 0x4f, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0xc0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, 0x03, 0x04, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48,
        0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x8a, 0x9c, 0x38, 0x62, 0x6b, 0xb0, 0xa0, 0x47, 0x07, 0x18, 0xd1, 0xb6, 0xc5, 0xf7, 0x15, 0x44, 0x58, 0x49, 0x4c, 0x5c, 0x07, 0x00, 0x00,
        0x66, 0x00, 0x00, 0x00, 0xd7, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x06, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x44, 0x07, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00,
        0xce, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c,
        0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x18, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xc4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x62, 0x88, 0x48, 0x90, 0x14, 0x20,
        0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x23, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x31, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00,
        0x08, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x6d, 0x30, 0x86, 0xff, 0xff, 0xff, 0xff, 0x1f,
        0x00, 0x09, 0xa8, 0x00, 0x49, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
        0x32, 0x22, 0x88, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x23, 0xa4, 0x84, 0x04, 0x13, 0x23, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8c, 0x8c, 0x0b, 0x84, 0xc4, 0x4c, 0x10, 0x88, 0xc1, 0x08,
        0x40, 0x09, 0x00, 0x0a, 0x66, 0x00, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x29, 0xc6, 0x40, 0x10, 0x44, 0x41, 0x90, 0x41, 0xc5, 0x3d, 0xc3, 0xe5, 0x4f, 0xd8, 0x43, 0x48, 0x7e, 0x08, 0x34, 0xc3,
        0x42, 0xa0, 0x00, 0x29, 0x0a, 0x40, 0x24, 0x49, 0x32, 0x0c, 0xc3, 0x30, 0x90, 0x72, 0xd4, 0x70, 0xf9, 0x13, 0xf6, 0x10, 0x92, 0xcf, 0x6d, 0x54, 0xb1, 0x12, 0x93, 0x5f, 0xdc, 0x36, 0x22, 0x86,
        0x61, 0x18, 0x0a, 0xc1, 0x10, 0x09, 0x41, 0xcd, 0x6d, 0xc3, 0xe5, 0x4f, 0xd8, 0x43, 0x48, 0xfe, 0x4a, 0x48, 0x0e, 0x15, 0x09, 0x44, 0x1a, 0x39, 0x0f, 0x11, 0x4d, 0x08, 0x21, 0x21, 0x81, 0x20,
        0x0a, 0x91, 0x10, 0xc9, 0x43, 0xd0, 0x41, 0xc3, 0xe5, 0x4f, 0xd8, 0x43, 0x48, 0xfe, 0x4a, 0x48, 0x1b, 0xd2, 0x0c, 0x88, 0x20, 0x08, 0xa2, 0x98, 0x23, 0x08, 0x4a, 0x91, 0x10, 0x12, 0x31, 0x11,
        0x35, 0x10, 0x30, 0x53, 0x18, 0x8c, 0x03, 0x3b, 0x84, 0xc3, 0x3c, 0xcc, 0x83, 0x1b, 0xd0, 0x42, 0x39, 0xe0, 0x03, 0x3d, 0xd4, 0x83, 0x3c, 0x94, 0x83, 0x1c, 0x90, 0x02, 0x1f, 0x98, 0x03, 0x3b,
        0xbc, 0x43, 0x38, 0xd0, 0x83, 0x1f, 0xe8, 0x81, 0x1e, 0xb4, 0x43, 0x3a, 0xc0, 0xc3, 0x3c, 0xfc, 0x02, 0x3d, 0xe4, 0x03, 0x3c, 0x94, 0x03, 0x0a, 0x88, 0x99, 0xac, 0x71, 0x60, 0x87, 0x70, 0x98,
        0x87, 0x79, 0x70, 0x03, 0x5a, 0x28, 0x07, 0x7c, 0xa0, 0x87, 0x7a, 0x90, 0x87, 0x72, 0x90, 0x03, 0x52, 0xe0, 0x03, 0x73, 0x60, 0x87, 0x77, 0x08, 0x07, 0x7a, 0xf0, 0x03, 0x24, 0x0c, 0x17, 0x61,
        0x33, 0x69, 0xe3, 0xc0, 0x0e, 0xe1, 0x30, 0x0f, 0xf3, 0xe0, 0x06, 0xa6, 0x50, 0x0e, 0xe5, 0x40, 0x0e, 0xe2, 0x10, 0x0e, 0xe3, 0xb0, 0x0e, 0xb4, 0x50, 0x0e, 0xf8, 0x40, 0x0f, 0xf5, 0x20, 0x0f,
        0xe5, 0x20, 0x07, 0xa4, 0xc0, 0x07, 0x70, 0xe0, 0x07, 0x28, 0x20, 0x48, 0x1b, 0x46, 0x10, 0x86, 0x23, 0xb8, 0x80, 0x2a, 0xd0, 0xc0, 0x0d, 0x03, 0x75, 0x37, 0x49, 0x53, 0x44, 0x09, 0x93, 0xcf,
        0x02, 0xcc, 0xb3, 0x10, 0x11, 0x3b, 0x01, 0x13, 0x81, 0x02, 0x82, 0xbe, 0x14, 0x20, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0,
        0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07,
        0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90,
        0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6,
        0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x14, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x18, 0xf2, 0x34, 0x40, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, 0x81, 0x80, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc8, 0x43, 0x01, 0x01,
        0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x16, 0x08, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x22,
        0x4a, 0xa0, 0x18, 0xca, 0x61, 0x04, 0xa0, 0x08, 0x4a, 0xa2, 0x44, 0x0a, 0xa4, 0x0c, 0xa8, 0x28, 0x89, 0x32, 0x28, 0x84, 0x11, 0x00, 0x9a, 0x46, 0x00, 0x28, 0x9b, 0x01, 0xa0, 0x6d, 0x06, 0x80,
        0xbc, 0x19, 0x00, 0x02, 0x67, 0x00, 0x28, 0x1c, 0x4b, 0x20, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec,
        0xed, 0x4d, 0x0c, 0x24, 0xc6, 0xe5, 0xc6, 0x45, 0x46, 0x26, 0x46, 0xc6, 0x85, 0x06, 0x06, 0x04, 0xa5, 0x0c, 0x86, 0x66, 0xc6, 0x8c, 0x26, 0x2c, 0x46, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x08,
        0x63, 0x82, 0x40, 0x1c, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x10, 0xc8, 0x06, 0x61, 0x30, 0x28, 0xc0, 0xcd, 0x6d, 0x18, 0x10, 0x82, 0x98, 0x20, 0x10, 0xc9, 0x04, 0x21, 0xa3, 0x08, 0x4c, 0x10, 0x08,
        0x65, 0x82, 0x40, 0x2c, 0x1b, 0x04, 0xc5, 0xd9, 0x90, 0x28, 0x0b, 0xa3, 0x28, 0x43, 0xa3, 0x3c, 0x1b, 0x02, 0x68, 0x82, 0xb0, 0x55, 0x13, 0x04, 0x82, 0x99, 0x20, 0x4c, 0xd3, 0x06, 0xa1, 0x51,
        0x36, 0x2c, 0x8a, 0xc4, 0x28, 0xca, 0x30, 0x51, 0x14, 0x55, 0x6d, 0x08, 0xac, 0x09, 0x82, 0x67, 0x4d, 0x10, 0x88, 0x66, 0x03, 0xa2, 0x60, 0x8c, 0xa2, 0x0c, 0x19, 0xb0, 0x21, 0xd0, 0x26, 0x08,
        0x60, 0x70, 0x6d, 0x40, 0x14, 0x8e, 0x51, 0x94, 0x41, 0x01, 0x36, 0x04, 0xdd, 0x06, 0x22, 0xba, 0x36, 0x6f, 0x82, 0x10, 0x06, 0xd8, 0x86, 0x00, 0x0c, 0x26, 0x08, 0x02, 0x40, 0xa2, 0x2d, 0x2c,
        0xcd, 0x8d, 0xcb, 0x94, 0xd5, 0x17, 0xd4, 0xdb, 0x5c, 0x1a, 0x5d, 0xda, 0x9b, 0xdb, 0x04, 0xa1, 0x78, 0x26, 0x08, 0x05, 0xb4, 0x21, 0x50, 0x26, 0x08, 0x45, 0x34, 0x41, 0x28, 0xa4, 0x09, 0x02,
        0xe1, 0x6c, 0x10, 0xd4, 0x40, 0x0d, 0x36, 0x2c, 0x0a, 0x19, 0x94, 0x81, 0x19, 0x9c, 0x01, 0x1a, 0x0c, 0x68, 0xa0, 0xa4, 0xc1, 0x1a, 0x6c, 0x08, 0xd8, 0x60, 0xc3, 0xd0, 0x06, 0x00, 0xb0, 0xa1,
        0x10, 0x83, 0x31, 0x70, 0x83, 0x0f, 0xa8, 0xc2, 0xc6, 0x66, 0xd7, 0xe6, 0x92, 0x46, 0x56, 0xe6, 0x46, 0x37, 0x25, 0x08, 0xaa, 0x90, 0xe1, 0xb9, 0xd8, 0x95, 0xc9, 0xcd, 0xa5, 0xbd, 0xb9, 0x4d,
        0x09, 0x88, 0x26, 0x64, 0x78, 0x2e, 0x76, 0x61, 0x6c, 0x76, 0x65, 0x72, 0x53, 0x02, 0xa3, 0x0e, 0x19, 0x9e, 0xcb, 0x1c, 0x5a, 0x18, 0x59, 0x99, 0x5c, 0xd3, 0x1b, 0x59, 0x19, 0xdb, 0x94, 0x00,
        0x29, 0x43, 0x86, 0xe7, 0x22, 0x57, 0x36, 0xf7, 0x56, 0x27, 0x37, 0x56, 0x36, 0x37, 0x25, 0xf0, 0xea, 0x90, 0xe1, 0xb9, 0xd8, 0xa5, 0x95, 0xdd, 0x25, 0x91, 0x4d, 0xd1, 0x85, 0xd1, 0x95, 0x4d,
        0x09, 0xc0, 0xa0, 0x0e, 0x19, 0x9e, 0x4b, 0x99, 0x1b, 0x9d, 0x5c, 0x1e, 0xd4, 0x5b, 0x9a, 0x1b, 0xdd, 0xdc, 0x94, 0xc0, 0x0d, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
        0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10,
        0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03,
        0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e,
        0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b,
        0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90,
        0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e,
        0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca,
        0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82,
        0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06,
        0xf6, 0x10, 0x0e, 0xf2, 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x46, 0x40, 0x0d, 0x97, 0xef, 0x3c, 0x3e, 0xd0,
        0x34, 0xce, 0x04, 0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, 0xd8, 0xc0, 0x36, 0x5c, 0xbe, 0xf3, 0xf8, 0x42, 0x40, 0x15, 0x05, 0x11, 0x95, 0x0e, 0x30, 0x94, 0x84, 0x01, 0x08, 0x98, 0x5f, 0xdc, 0xb6,
        0x15, 0x74, 0xc3, 0xe5, 0x3b, 0x8f, 0x2f, 0x44, 0x04, 0x30, 0x11, 0x21, 0xd0, 0x0c, 0x0b, 0xf1, 0x45, 0x0e, 0xb3, 0x21, 0xcd, 0x80, 0x34, 0x86, 0x05, 0x4c, 0xc3, 0xe5, 0x3b, 0x8f, 0xbf, 0x38,
        0xc0, 0x20, 0x36, 0x0f, 0x35, 0xf9, 0xc5, 0x6d, 0x9b, 0x80, 0x36, 0x5c, 0xbe, 0xf3, 0xf8, 0x56, 0x84, 0x4c, 0x04, 0x0b, 0x30, 0xcf, 0x42, 0x44, 0x1f, 0x41, 0x0c, 0x01, 0x20, 0x28, 0x06, 0x40,
        0x30, 0x00, 0xd2, 0x00, 0x61, 0x20, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x54, 0x14, 0x01, 0x11, 0x25, 0x3b, 0x50, 0xb0,
        0x03, 0x85, 0x30, 0x03, 0x50, 0x1a, 0x65, 0x57, 0xa2, 0x40, 0x25, 0x49, 0x50, 0x1c, 0xc5, 0x2d, 0x40, 0x45, 0x09, 0xd0, 0x30, 0x03, 0x40, 0xcf, 0x1c, 0x82, 0xd7, 0xcc, 0x21, 0x80, 0x41, 0x32,
        0x87, 0xa0, 0x84, 0xc1, 0x1c, 0x82, 0x18, 0x24, 0x24, 0xcd, 0x41, 0x24, 0x49, 0x42, 0x06, 0x23, 0x00, 0x73, 0x10, 0x49, 0x92, 0x40, 0x73, 0x10, 0x49, 0x92, 0x64, 0x00, 0x23, 0x06, 0x08, 0x00,
        0x82, 0x60, 0x40, 0xa5, 0x01, 0x45, 0x94, 0xc1, 0x36, 0x62, 0x80, 0x00, 0x20, 0x08, 0x06, 0x94, 0x1a, 0x54, 0x84, 0x19, 0x70, 0x23, 0x06, 0x08, 0x00, 0x82, 0x60, 0x40, 0xad, 0x81, 0x45, 0x9c,
        0x41, 0x37, 0x62, 0x80, 0x00, 0x20, 0x08, 0x06, 0x14, 0x1b, 0x5c, 0x04, 0x1a, 0x78, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0x00, 0xb9, 0xc1, 0x15, 0x30, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x60,
        0xc8, 0xc1, 0xa5, 0x06, 0x6a, 0x10, 0x06, 0xd6, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x73, 0x80, 0xad, 0xc1, 0x1a, 0x40, 0xd7, 0x09, 0x04, 0x9d, 0x40, 0xd0, 0x88, 0xc1, 0x01, 0x80, 0x20,
        0x18, 0x34, 0x74, 0x80, 0x15, 0x6e, 0x30, 0x9a, 0x10, 0x00, 0xa3, 0x09, 0x42, 0x70, 0xc5, 0x60, 0xa3, 0x09, 0x84, 0x60, 0x81, 0x20, 0x1f, 0x0b, 0x0a, 0xf8, 0x1c, 0x32, 0x98, 0x11, 0x81, 0x7c,
        0x2c, 0x38, 0xe0, 0x33, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x50, 0x1f, 0x98, 0xc1, 0xa4, 0x8d, 0x18, 0x1c, 0x00, 0x08, 0x82, 0x01, 0xe4, 0x07, 0x67, 0x30, 0x69, 0x23, 0x06, 0x07, 0x00, 0x82,
        0x60, 0x00, 0xfd, 0x01, 0x1a, 0x4c, 0xda, 0x88, 0x41, 0x03, 0x80, 0x20, 0x18, 0x28, 0xa2, 0x10, 0x06, 0x83, 0x10, 0x1c, 0xc4, 0xf7, 0x7d, 0x08, 0x00, 0x00, 0x00, 0x00,
    };
    static const D3D12_SHADER_BYTECODE ps_code_non_bias_dxil = SHADER_BYTECODE(ps_code_non_bias);

    static const BYTE ps_code_bias[] =
    {
#if 0
    Texture2D<float> T : register(t0);
    SamplerState S : register(s0);
    FeedbackTexture2D<SAMPLER_FEEDBACK_MIN_MIP> FB : register(u0);

    cbuffer Cbuf : register(b0) { float2 uv; float grad; float bias; };

    void main(float4 pos : SV_Position)
    {
            int2 ipos = int2(pos.xy);
            float2 modified_uv = uv;
            modified_uv.x += float(ipos.x) * grad;
            modified_uv.y += float(ipos.y) * grad;

            FB.WriteSamplerFeedbackBias(T, S, modified_uv, bias);
    }
#endif
        0x44, 0x58, 0x42, 0x43, 0x72, 0xe9, 0x82, 0x5d, 0x31, 0xf2, 0x66, 0x21, 0x5a, 0x54, 0x5a, 0xf7, 0x47, 0x19, 0x31, 0x13, 0x01, 0x00, 0x00, 0x00, 0xf4, 0x08, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
        0x38, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74,
        0x69, 0x6f, 0x6e, 0x00, 0x4f, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0xc0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, 0x03, 0x04, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48,
        0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x4c, 0xb0, 0x4e, 0x39, 0xe8, 0xb2, 0x82, 0xc2, 0xc8, 0x7a, 0xb9, 0x51, 0xf9, 0x43, 0xc3, 0x44, 0x58, 0x49, 0x4c, 0x74, 0x07, 0x00, 0x00,
        0x66, 0x00, 0x00, 0x00, 0xdd, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x06, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x5c, 0x07, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00,
        0xd4, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c,
        0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x18, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xc4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x62, 0x88, 0x48, 0x90, 0x14, 0x20,
        0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x23, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x31, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00,
        0x08, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x6d, 0x30, 0x86, 0xff, 0xff, 0xff, 0xff, 0x1f,
        0x00, 0x09, 0xa8, 0x00, 0x49, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
        0x32, 0x22, 0x88, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x23, 0xa4, 0x84, 0x04, 0x13, 0x23, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8c, 0x8c, 0x0b, 0x84, 0xc4, 0x4c, 0x10, 0x88, 0xc1, 0x08,
        0x40, 0x09, 0x00, 0x0a, 0x66, 0x00, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x29, 0xc6, 0x40, 0x10, 0x44, 0x41, 0x90, 0x41, 0xc5, 0x3d, 0xc3, 0xe5, 0x4f, 0xd8, 0x43, 0x48, 0x7e, 0x08, 0x34, 0xc3,
        0x42, 0xa0, 0x00, 0x29, 0x0b, 0x40, 0x24, 0x49, 0x32, 0x0c, 0xc3, 0x30, 0x0c, 0xa4, 0x1c, 0x35, 0x5c, 0xfe, 0x84, 0x3d, 0x84, 0xe4, 0x73, 0x1b, 0x55, 0xac, 0xc4, 0xe4, 0x17, 0xb7, 0x8d, 0x88,
        0x61, 0x18, 0x86, 0x42, 0x30, 0x44, 0x42, 0x50, 0x73, 0xdb, 0x70, 0xf9, 0x13, 0xf6, 0x10, 0x92, 0xbf, 0x12, 0x92, 0x43, 0x45, 0x02, 0x91, 0x46, 0xce, 0x43, 0x44, 0x13, 0x42, 0x48, 0x48, 0x20,
        0x88, 0x42, 0x24, 0x44, 0xf2, 0x10, 0x74, 0xd0, 0x70, 0xf9, 0x13, 0xf6, 0x10, 0x92, 0xbf, 0x12, 0xd2, 0x86, 0x34, 0x03, 0x22, 0x08, 0x82, 0x28, 0xe6, 0x08, 0x82, 0x52, 0x24, 0x84, 0x44, 0x4c,
        0x44, 0x0d, 0x04, 0xcc, 0x14, 0x06, 0xe3, 0xc0, 0x0e, 0xe1, 0x30, 0x0f, 0xf3, 0xe0, 0x06, 0xb4, 0x50, 0x0e, 0xf8, 0x40, 0x0f, 0xf5, 0x20, 0x0f, 0xe5, 0x20, 0x07, 0xa4, 0xc0, 0x07, 0xe6, 0xc0,
        0x0e, 0xef, 0x10, 0x0e, 0xf4, 0xe0, 0x07, 0x7a, 0xa0, 0x07, 0xed, 0x90, 0x0e, 0xf0, 0x30, 0x0f, 0xbf, 0x40, 0x0f, 0xf9, 0x00, 0x0f, 0xe5, 0x80, 0x02, 0x62, 0x26, 0x6b, 0x1c, 0xd8, 0x21, 0x1c,
        0xe6, 0x61, 0x1e, 0xdc, 0x80, 0x16, 0xca, 0x01, 0x1f, 0xe8, 0xa1, 0x1e, 0xe4, 0xa1, 0x1c, 0xe4, 0x80, 0x14, 0xf8, 0xc0, 0x1c, 0xd8, 0xe1, 0x1d, 0xc2, 0x81, 0x1e, 0xfc, 0x00, 0x09, 0xc3, 0x45,
        0xd8, 0x4c, 0xda, 0x38, 0xb0, 0x43, 0x38, 0xcc, 0xc3, 0x3c, 0xb8, 0x81, 0x29, 0x94, 0x43, 0x39, 0x90, 0x83, 0x38, 0x84, 0xc3, 0x38, 0xac, 0x03, 0x2d, 0x94, 0x03, 0x3e, 0xd0, 0x43, 0x3d, 0xc8,
        0x43, 0x39, 0xc8, 0x01, 0x29, 0xf0, 0x01, 0x1c, 0xf8, 0x01, 0x0a, 0x08, 0xd2, 0x86, 0x11, 0x84, 0xe1, 0x08, 0x2e, 0xa0, 0x0a, 0x34, 0x70, 0xc3, 0x40, 0xdd, 0x4d, 0xd2, 0x14, 0x51, 0xc2, 0xe4,
        0xb3, 0x00, 0xf3, 0x2c, 0x44, 0xc4, 0x4e, 0xc0, 0x44, 0xa0, 0x80, 0xa0, 0x2f, 0x05, 0x08, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0,
        0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07,
        0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90,
        0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6,
        0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x14, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x18, 0xf2, 0x34, 0x40, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, 0x81, 0x80, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc8, 0x43, 0x01, 0x01,
        0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x16, 0x08, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x22,
        0x4a, 0xa0, 0x18, 0xca, 0x61, 0x04, 0xa0, 0x08, 0x4a, 0xa2, 0x44, 0x0a, 0xa4, 0x0c, 0xa8, 0x28, 0x89, 0x32, 0x28, 0x84, 0x11, 0x00, 0x9a, 0x46, 0x00, 0x28, 0x9b, 0x01, 0xa0, 0x6d, 0x06, 0x80,
        0xbc, 0x19, 0x00, 0x02, 0x67, 0x00, 0x28, 0x1c, 0x4b, 0x20, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec,
        0xed, 0x4d, 0x0c, 0x24, 0xc6, 0xe5, 0xc6, 0x45, 0x46, 0x26, 0x46, 0xc6, 0x85, 0x06, 0x06, 0x04, 0xa5, 0x0c, 0x86, 0x66, 0xc6, 0x8c, 0x26, 0x2c, 0x46, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x08,
        0x63, 0x82, 0x40, 0x1c, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x10, 0xc8, 0x06, 0x61, 0x30, 0x28, 0xc0, 0xcd, 0x6d, 0x18, 0x10, 0x82, 0x98, 0x20, 0x10, 0xc9, 0x04, 0x21, 0xa3, 0x08, 0x4c, 0x10, 0x08,
        0x65, 0x82, 0x40, 0x2c, 0x1b, 0x04, 0xc5, 0xd9, 0x90, 0x28, 0x0b, 0xa3, 0x28, 0x43, 0xa3, 0x3c, 0x1b, 0x02, 0x68, 0x82, 0xb0, 0x55, 0x13, 0x04, 0x82, 0x99, 0x20, 0x4c, 0xd3, 0x06, 0xa1, 0x51,
        0x36, 0x2c, 0x8a, 0xc4, 0x28, 0xca, 0x30, 0x51, 0x14, 0x55, 0x6d, 0x08, 0xac, 0x09, 0x82, 0x67, 0x4d, 0x10, 0x88, 0x66, 0x03, 0xa2, 0x60, 0x8c, 0xa2, 0x0c, 0x19, 0xb0, 0x21, 0xd0, 0x26, 0x08,
        0x60, 0x70, 0x6d, 0x40, 0x14, 0x8e, 0x51, 0x94, 0x41, 0x01, 0x36, 0x04, 0xdd, 0x06, 0x22, 0xba, 0x36, 0x6f, 0x82, 0x10, 0x06, 0xd8, 0x86, 0x00, 0x0c, 0x26, 0x08, 0x02, 0x40, 0xa2, 0x2d, 0x2c,
        0xcd, 0x8d, 0xcb, 0x94, 0xd5, 0x17, 0xd4, 0xdb, 0x5c, 0x1a, 0x5d, 0xda, 0x9b, 0xdb, 0x04, 0xa1, 0x78, 0x26, 0x08, 0x05, 0xb4, 0x21, 0x50, 0x26, 0x08, 0x45, 0x34, 0x41, 0x28, 0xa4, 0x09, 0x02,
        0xe1, 0x6c, 0x10, 0xd4, 0x40, 0x0d, 0x36, 0x2c, 0x0a, 0x19, 0x94, 0x81, 0x19, 0x9c, 0x01, 0x1a, 0x0c, 0x68, 0xa0, 0xa4, 0xc1, 0x1a, 0x6c, 0x08, 0xd8, 0x60, 0xc3, 0xd0, 0x06, 0x00, 0xb0, 0xa1,
        0x10, 0x83, 0x31, 0x70, 0x83, 0x0f, 0xa8, 0xc2, 0xc6, 0x66, 0xd7, 0xe6, 0x92, 0x46, 0x56, 0xe6, 0x46, 0x37, 0x25, 0x08, 0xaa, 0x90, 0xe1, 0xb9, 0xd8, 0x95, 0xc9, 0xcd, 0xa5, 0xbd, 0xb9, 0x4d,
        0x09, 0x88, 0x26, 0x64, 0x78, 0x2e, 0x76, 0x61, 0x6c, 0x76, 0x65, 0x72, 0x53, 0x02, 0xa3, 0x0e, 0x19, 0x9e, 0xcb, 0x1c, 0x5a, 0x18, 0x59, 0x99, 0x5c, 0xd3, 0x1b, 0x59, 0x19, 0xdb, 0x94, 0x00,
        0x29, 0x43, 0x86, 0xe7, 0x22, 0x57, 0x36, 0xf7, 0x56, 0x27, 0x37, 0x56, 0x36, 0x37, 0x25, 0xf0, 0xea, 0x90, 0xe1, 0xb9, 0xd8, 0xa5, 0x95, 0xdd, 0x25, 0x91, 0x4d, 0xd1, 0x85, 0xd1, 0x95, 0x4d,
        0x09, 0xc0, 0xa0, 0x0e, 0x19, 0x9e, 0x4b, 0x99, 0x1b, 0x9d, 0x5c, 0x1e, 0xd4, 0x5b, 0x9a, 0x1b, 0xdd, 0xdc, 0x94, 0xc0, 0x0d, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
        0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10,
        0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03,
        0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e,
        0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b,
        0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90,
        0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e,
        0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca,
        0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82,
        0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06,
        0xf6, 0x10, 0x0e, 0xf2, 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x46, 0x40, 0x0d, 0x97, 0xef, 0x3c, 0x3e, 0xd0,
        0x34, 0xce, 0x04, 0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, 0xd8, 0xc0, 0x36, 0x5c, 0xbe, 0xf3, 0xf8, 0x42, 0x40, 0x15, 0x05, 0x11, 0x95, 0x0e, 0x30, 0x94, 0x84, 0x01, 0x08, 0x98, 0x5f, 0xdc, 0xb6,
        0x15, 0x74, 0xc3, 0xe5, 0x3b, 0x8f, 0x2f, 0x44, 0x04, 0x30, 0x11, 0x21, 0xd0, 0x0c, 0x0b, 0xf1, 0x45, 0x0e, 0xb3, 0x21, 0xcd, 0x80, 0x34, 0x86, 0x05, 0x4c, 0xc3, 0xe5, 0x3b, 0x8f, 0xbf, 0x38,
        0xc0, 0x20, 0x36, 0x0f, 0x35, 0xf9, 0xc5, 0x6d, 0x9b, 0x80, 0x37, 0x5c, 0xbe, 0xf3, 0xf8, 0x56, 0x84, 0x4c, 0x04, 0x0b, 0x30, 0xcf, 0x42, 0x44, 0x1f, 0x41, 0x0c, 0x01, 0x20, 0x28, 0x1b, 0x02,
        0x48, 0x06, 0x40, 0x30, 0x00, 0xd2, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x54, 0x14, 0x01, 0x11,
        0x25, 0x3b, 0x50, 0xb0, 0x03, 0x85, 0x30, 0x03, 0x50, 0x76, 0xa5, 0x51, 0xa2, 0x40, 0x25, 0x49, 0x50, 0x1c, 0xe5, 0x2d, 0x40, 0x45, 0x09, 0xd0, 0x30, 0x03, 0x40, 0xcf, 0x1c, 0xc2, 0xd7, 0xcc,
        0x21, 0x80, 0x41, 0x32, 0x87, 0xa0, 0x84, 0xc1, 0x1c, 0x82, 0x18, 0x24, 0x24, 0xcd, 0x41, 0x24, 0x49, 0x42, 0x06, 0x23, 0x00, 0x73, 0x10, 0x49, 0x92, 0x40, 0x73, 0x10, 0x49, 0x92, 0x64, 0x00,
        0x23, 0x06, 0x08, 0x00, 0x82, 0x60, 0x40, 0xa5, 0x01, 0x45, 0x94, 0xc1, 0x36, 0x62, 0x80, 0x00, 0x20, 0x08, 0x06, 0x94, 0x1a, 0x54, 0x84, 0x19, 0x70, 0x23, 0x06, 0x08, 0x00, 0x82, 0x60, 0x40,
        0xad, 0x81, 0x45, 0x9c, 0x41, 0x37, 0x62, 0x80, 0x00, 0x20, 0x08, 0x06, 0x14, 0x1b, 0x5c, 0x04, 0x1a, 0x78, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0x00, 0xb9, 0xc1, 0x15, 0x30, 0x23, 0x06, 0x09,
        0x00, 0x82, 0x60, 0x60, 0xc8, 0xc1, 0xa5, 0x06, 0x6a, 0x10, 0x06, 0xd6, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x73, 0x80, 0xad, 0xc1, 0x1a, 0x40, 0xd7, 0x09, 0x04, 0x9d, 0x40, 0xd0, 0x88,
        0xc1, 0x01, 0x80, 0x20, 0x18, 0x34, 0x74, 0x90, 0x15, 0x6e, 0x30, 0x9a, 0x10, 0x00, 0xa3, 0x09, 0x42, 0x70, 0xc5, 0x60, 0xa3, 0x09, 0x84, 0x60, 0x81, 0x20, 0x1f, 0x0b, 0x0a, 0xf8, 0x1c, 0x32,
        0x98, 0x11, 0x81, 0x7c, 0x2c, 0x38, 0xe0, 0x33, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x8d, 0x1f, 0x8c, 0xc1, 0x83, 0x07, 0xa3, 0x09, 0xc1, 0x30, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0xd0, 0x1f,
        0xa0, 0x41, 0xc5, 0x8d, 0x18, 0x1c, 0x00, 0x08, 0x82, 0x01, 0x04, 0x0a, 0x69, 0x50, 0x71, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0x00, 0x85, 0x82, 0x1a, 0x54, 0xdc, 0x88, 0x81, 0x03, 0x80, 0x20,
        0x18, 0x28, 0xa4, 0x30, 0x06, 0x83, 0x10, 0x24, 0x46, 0x18, 0x84, 0x01, 0x11, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
    };
    static const D3D12_SHADER_BYTECODE ps_code_bias_dxil = SHADER_BYTECODE(ps_code_bias);

#define TEX_WIDTH 2048
#define TEX_HEIGHT 2048
#define MIP_REGION_WIDTH 32
#define MIP_REGION_HEIGHT 32
#define FEEDBACK_WIDTH (TEX_WIDTH / MIP_REGION_WIDTH)
#define FEEDBACK_HEIGHT (TEX_HEIGHT / MIP_REGION_HEIGHT)
#define TEX_MIP_LEVELS 3

    static const int coords[][4] = {
        { MIP_REGION_WIDTH * 0 + 16, MIP_REGION_HEIGHT * 0 + 16, 2, 0 }, /* Gradient of two texels -> LOD 1 */
        { MIP_REGION_WIDTH * 4 + 16, MIP_REGION_HEIGHT * 0 + 16, 0, +14 }, /* Empty gradient with LOD bias -> LOD -inf still */
        { MIP_REGION_WIDTH * 0 + 16, MIP_REGION_HEIGHT * 4 + 16, 2, -1 }, /* Negative bias -> LOD 0 */
        { MIP_REGION_WIDTH * 4 + 16, MIP_REGION_HEIGHT * 4 + 16, 1, 3 }, /* Positive bias -> LOD 2 due to clamp */
        { MIP_REGION_WIDTH * 8 + 16, MIP_REGION_HEIGHT * 4 + 16, 1, 1 }, /* LOD 1 due to bias */
    };

    uint8_t expected_amd_style[FEEDBACK_HEIGHT][FEEDBACK_WIDTH];
    uint8_t expected_nv_style[FEEDBACK_HEIGHT][FEEDBACK_WIDTH];

    /* The spec allows for two styles of feedback. Either feedback is written once,
     * or it's written in a splat way so that the footprint touches (1 << LOD) x (1 << LOD) area in terms of mip regions.
     * See https://microsoft.github.io/DirectX-Specs/d3d/SamplerFeedback.html#minmip-feedback-map where it talks about:
     * "Note how the “01” may appear in the top left group of decoded texels, or in the top left texel only." */
    memset(expected_amd_style, 0xff, sizeof(expected_amd_style));
    memset(expected_nv_style, 0xff, sizeof(expected_nv_style));

    {
        int inner_x, inner_y;
        int tile_x, tile_y;

        for (i = 0; i < ARRAY_SIZE(coords); i++)
        {
            int effective_lod = (int)max(log2f(coords[i][2]) + (biased ? coords[i][3] : 0), 0.0f);
            effective_lod = min(effective_lod, TEX_MIP_LEVELS - 1);

            tile_x = (coords[i][0] % TEX_WIDTH) / MIP_REGION_WIDTH;
            tile_y = (coords[i][1] % TEX_HEIGHT) / MIP_REGION_HEIGHT;

            /* AMD just writes one texel here. */
            expected_amd_style[tile_y][tile_x] = min(expected_amd_style[tile_y][tile_x], effective_lod);

            /* NV writes a larger footprint. My working theory is that they write once to a hierarchical data structure which gets expanded in resolve. */
            tile_x &= ~((1 << effective_lod) - 1);
            tile_y &= ~((1 << effective_lod) - 1);
            for (inner_y = tile_y; inner_y < tile_y + (1 << effective_lod); inner_y++)
            {
                for (inner_x = tile_x; inner_x < tile_x + (1 << effective_lod); inner_x++)
                {
                    expected_nv_style[inner_y][inner_x] = min(expected_nv_style[inner_y][inner_x], effective_lod);
                }
            }
        }
    }

    memset(&context_desc, 0, sizeof(context_desc));
    context_desc.no_pipeline = true;
    context_desc.no_render_target = true;
    context_desc.no_root_signature = true;
    if (!init_test_context(&context, &context_desc))
        return;


    if (FAILED(ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS7, &features7, sizeof(features7))) ||
        features7.SamplerFeedbackTier < D3D12_SAMPLER_FEEDBACK_TIER_0_9)
    {
        skip("Sampler feedback not supported.\n");
        destroy_test_context(&context);
        return;
    }

    hr = ID3D12Device_QueryInterface(context.device, &IID_ID3D12Device8, (void **)&device8);
    ok(SUCCEEDED(hr), "Failed to query Device8, hr #%x.\n", hr);
    hr = ID3D12GraphicsCommandList_QueryInterface(context.list, &IID_ID3D12GraphicsCommandList1, (void **)&list1);
    ok(SUCCEEDED(hr), "Failed to query GraphicsCommandList1, hr #%x.\n", hr);

    memset(&rs_desc, 0, sizeof(rs_desc));
    memset(desc_range, 0, sizeof(desc_range));
    memset(rs_param, 0, sizeof(rs_param));
    memset(&static_sampler, 0, sizeof(static_sampler));
    rs_desc.NumParameters = ARRAY_SIZE(rs_param);
    rs_desc.pParameters = rs_param;
    rs_desc.NumStaticSamplers = 1;
    rs_desc.pStaticSamplers = &static_sampler;

    static_sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
    static_sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
    static_sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
    static_sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
    static_sampler.MaxLOD = 1000.0f;

    rs_param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
    rs_param[0].DescriptorTable.NumDescriptorRanges = ARRAY_SIZE(desc_range);
    rs_param[0].DescriptorTable.pDescriptorRanges = desc_range;
    desc_range[0].NumDescriptors = 1;
    desc_range[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
    desc_range[1].NumDescriptors = 1;
    desc_range[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
    desc_range[1].OffsetInDescriptorsFromTableStart = 1;
    rs_param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
    rs_param[1].Constants.Num32BitValues = 4;

    create_root_signature(context.device, &rs_desc, &context.root_signature);

    init_pipeline_state_desc_dxil(&pso_desc, context.root_signature, DXGI_FORMAT_UNKNOWN, &vs_code_dxil, biased ? &ps_code_bias_dxil : &ps_code_non_bias_dxil, NULL);
    pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
    pso_desc.DepthStencilState.DepthEnable = FALSE;
    pso_desc.DepthStencilState.StencilEnable = FALSE;
    pso_desc.DSVFormat = DXGI_FORMAT_UNKNOWN;
    hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&context.pipeline_state);
    ok(SUCCEEDED(hr), "Failed to create pipeline state, hr #%x.\n", hr);

    desc_heap = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2);
    desc_heap_cpu = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);

    resource = create_default_texture2d(context.device, TEX_WIDTH, TEX_HEIGHT, 1, TEX_MIP_LEVELS, DXGI_FORMAT_R8_UNORM, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
    resolve = create_default_texture2d(context.device, FEEDBACK_WIDTH, FEEDBACK_HEIGHT, 1, 1, DXGI_FORMAT_R8_UINT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_RESOLVE_DEST);

    memset(&desc, 0, sizeof(desc));
    memset(&heap_props, 0, sizeof(heap_props));

    heap_props.Type = D3D12_HEAP_TYPE_DEFAULT;
    desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    desc.SampleDesc.Count = 1;
    desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
    desc.Width = TEX_WIDTH;
    desc.Height = TEX_HEIGHT;
    desc.DepthOrArraySize = 1;
    desc.MipLevels = TEX_MIP_LEVELS;
    desc.SamplerFeedbackMipRegion.Width = MIP_REGION_WIDTH;
    desc.SamplerFeedbackMipRegion.Height = MIP_REGION_HEIGHT;
    desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
    desc.Format = DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE;
    hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, &desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, NULL, &IID_ID3D12Resource, (void **)&feedback);
    ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);

    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback, ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap));
    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback, ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap_cpu));

    {
        D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc;
        memset(&srv_desc, 0, sizeof(srv_desc));
        srv_desc.Format = DXGI_FORMAT_R8_UNORM;
        srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
        srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
        srv_desc.Texture2D.MipLevels = TEX_MIP_LEVELS; /* Verify that the SRV itself clamps the feedback that is written. */
        ID3D12Device_CreateShaderResourceView(context.device, resource, &srv_desc, get_cpu_descriptor_handle(&context, desc_heap, 1));
    }

    ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &desc_heap);

    {
        UINT zeroes[4] = { 0 }; /* Clear value is ignored. The actual clear value is opaque, but after a resolve, it should be 0xff. */
        ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(context.list,
            ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heap),
            ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap_cpu),
            feedback, zeroes, 0, NULL);
        uav_barrier(context.list, feedback);
    }

    ID3D12GraphicsCommandList_SetGraphicsRootSignature(context.list, context.root_signature);
    ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state);
    ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(context.list, 0, ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heap));
    ID3D12GraphicsCommandList_IASetPrimitiveTopology(context.list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    set_viewport(&vp, 0, 0, 2, 2, 0, 1);
    set_rect(&sci, 0, 0, 2, 2);
    ID3D12GraphicsCommandList_RSSetViewports(context.list, 1, &vp);
    ID3D12GraphicsCommandList_RSSetScissorRects(context.list, 1, &sci);

    for (i = 0; i < ARRAY_SIZE(coords); i++)
    {
        float normalized_coords[4] = { ((float)coords[i][0] + 0.5f) / TEX_WIDTH, ((float)coords[i][1] + 0.5f) / TEX_HEIGHT, (float)coords[i][2] / TEX_WIDTH, (float)coords[i][3] };
        ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(context.list, 1, 4, normalized_coords, 0);
        ID3D12GraphicsCommandList_DrawInstanced(context.list, 3, 1, 0, 0);
    }

    transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
    ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve, UINT_MAX, 0, 0, feedback, UINT_MAX, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
    transition_resource_state(context.list, resolve, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);

    get_texture_readback_with_command_list(resolve, 0, &rb, context.queue, context.list);

    for (y = 0; y < FEEDBACK_HEIGHT; y++)
    {
        for (x = 0; x < FEEDBACK_WIDTH; x++)
        {
            unsigned int value;
            value = get_readback_uint8(&rb, x, y);
            ok(value == expected_nv_style[y][x] || value == expected_amd_style[y][x],
                "Coord %u, %u: expected %u or %u, got %u.\n", x, y, expected_nv_style[y][x], expected_amd_style[y][x], value);
        }
    }

    release_resource_readback(&rb);

    ID3D12GraphicsCommandList1_Release(list1);
    ID3D12Resource_Release(resource);
    ID3D12Resource_Release(feedback);
    ID3D12Resource_Release(resolve);
    ID3D12DescriptorHeap_Release(desc_heap);
    ID3D12DescriptorHeap_Release(desc_heap_cpu);
    ID3D12Device8_Release(device8);
    destroy_test_context(&context);
#undef TEX_WIDTH
#undef TEX_HEIGHT
#undef MIP_REGION_WIDTH
#undef MIP_REGION_HEIGHT
#undef FEEDBACK_WIDTH
#undef FEEDBACK_HEIGHT
#undef TEX_MIP_LEVELS
}

void test_sampler_feedback_implicit_lod_aniso(void)
{
    D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
    D3D12_FEATURE_DATA_D3D12_OPTIONS7 features7;
    D3D12_STATIC_SAMPLER_DESC static_sampler;
    struct test_context_desc context_desc;
    D3D12_DESCRIPTOR_RANGE desc_range[2];
    ID3D12DescriptorHeap *desc_heap_cpu;
    D3D12_ROOT_SIGNATURE_DESC rs_desc;
    ID3D12GraphicsCommandList1 *list1;
    D3D12_ROOT_PARAMETER rs_param[2];
    D3D12_HEAP_PROPERTIES heap_props;
    ID3D12DescriptorHeap *desc_heap;
    struct test_context context;
    struct resource_readback rb;
    D3D12_RESOURCE_DESC1 desc;
    ID3D12Resource *resource;
    ID3D12Resource *feedback;
    ID3D12Resource *resolve;
    unsigned int x, y, i, j;
    ID3D12Device8 *device8;
    D3D12_VIEWPORT vp;
    D3D12_RECT sci;
    HRESULT hr;

    static const BYTE vs_code[] =
    {
#if 0
    float4 main(uint vid : SV_VertexID) : SV_Position
    {
            float4 pos;
            pos.x = -1.0 + 4.0 * (vid & 1);
            pos.y = -1.0 + 2.0 * (vid & 2);
            pos.z = 0.0;
            pos.w = 1.0;
            return pos;
    }
#endif
        0x44, 0x58, 0x42, 0x43, 0x82, 0xce, 0x0f, 0x3e, 0xe9, 0x14, 0x2e, 0xc7, 0xf8, 0x6e, 0xff, 0x4a, 0xb6, 0x6e, 0x4c, 0x87, 0x01, 0x00, 0x00, 0x00, 0x64, 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
        0x38, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x56, 0x65, 0x72, 0x74, 0x65,
        0x78, 0x49, 0x44, 0x00, 0x4f, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00,
        0x50, 0x53, 0x56, 0x30, 0x7c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x01,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, 0x03, 0x04, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0xf5, 0xdf, 0x57, 0x2b, 0x70, 0xd0, 0xf3, 0xed, 0x3a, 0xb1, 0x5e, 0x7a, 0xba, 0x23, 0x26,
        0x44, 0x58, 0x49, 0x4c, 0xfc, 0x04, 0x00, 0x00, 0x66, 0x00, 0x01, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x06, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xe4, 0x04, 0x00, 0x00,
        0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49,
        0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b,
        0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a,
        0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20,
        0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09,
        0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x30, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x39,
        0x02, 0x30, 0x98, 0x23, 0x40, 0x8a, 0x31, 0x33, 0x43, 0x43, 0x35, 0x03, 0x50, 0x0c, 0x98, 0x19, 0x3a, 0xc2, 0x81, 0x80, 0x1c, 0x18, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87,
        0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d,
        0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07,
        0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20,
        0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76,
        0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x05, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20,
        0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x9a,
        0x12, 0x28, 0x86, 0x72, 0x18, 0x01, 0x28, 0x83, 0xf2, 0x20, 0x2a, 0x85, 0x12, 0x18, 0x01, 0x28, 0x89, 0x32, 0x28, 0x04, 0xda, 0xb1, 0x86, 0x80, 0x18, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00,
        0x46, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0xe5, 0xc6, 0x45, 0x46, 0x26, 0x46, 0xc6, 0x85, 0x06, 0x06, 0x04,
        0xa5, 0x0c, 0x86, 0x66, 0xc6, 0x8c, 0x26, 0x2c, 0x46, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x86, 0x61, 0x82, 0x30, 0x10, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x0c, 0xc5, 0x06, 0x61, 0x30, 0x28, 0xd8,
        0xcd, 0x6d, 0x18, 0x10, 0x82, 0x98, 0x20, 0x2c, 0xcf, 0x86, 0x40, 0x99, 0x20, 0x08, 0x00, 0x0f, 0xbb, 0xb9, 0xaf, 0xb6, 0xb0, 0x34, 0xb7, 0x09, 0xc2, 0x60, 0x70, 0x99, 0xb2, 0xfa, 0xb2, 0x2a,
        0x93, 0xa3, 0x2b, 0xc3, 0x4b, 0x22, 0x9a, 0x20, 0x10, 0xc9, 0x04, 0x81, 0x50, 0x36, 0x04, 0xce, 0x04, 0x81, 0x58, 0x26, 0x08, 0xc3, 0xb1, 0x41, 0xa0, 0x86, 0x0d, 0x8b, 0xf3, 0x40, 0x91, 0x34,
        0x0d, 0x91, 0x33, 0x55, 0x1b, 0x02, 0x8b, 0xcb, 0x94, 0xd5, 0x17, 0xd4, 0xdb, 0x5c, 0x1a, 0x5d, 0xda, 0x9b, 0xdb, 0x04, 0x81, 0x60, 0x26, 0x08, 0x44, 0x33, 0x41, 0x20, 0x9c, 0x09, 0xc2, 0x80,
        0x6c, 0x10, 0x28, 0x6e, 0xc3, 0xe2, 0x60, 0x99, 0x26, 0x6d, 0xc3, 0xe6, 0x4c, 0xdd, 0x86, 0xc0, 0xdb, 0x30, 0x5c, 0x1f, 0xb0, 0xa1, 0x60, 0x1a, 0x30, 0x00, 0x80, 0x2a, 0x6c, 0x6c, 0x76, 0x6d,
        0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x82, 0xa0, 0x0a, 0x19, 0x9e, 0x8b, 0x5d, 0x99, 0xdc, 0x5c, 0xda, 0x9b, 0xdb, 0x94, 0x80, 0x68, 0x42, 0x86, 0xe7, 0x62, 0x17, 0xc6, 0x66, 0x57, 0x26,
        0x37, 0x25, 0x30, 0xea, 0x90, 0xe1, 0xb9, 0xcc, 0xa1, 0x85, 0x91, 0x95, 0xc9, 0x35, 0xbd, 0x91, 0x95, 0xb1, 0x4d, 0x09, 0x90, 0x3a, 0x64, 0x78, 0x2e, 0x76, 0x69, 0x65, 0x77, 0x49, 0x64, 0x53,
        0x74, 0x61, 0x74, 0x65, 0x53, 0x02, 0xa5, 0x0e, 0x19, 0x9e, 0x4b, 0x99, 0x1b, 0x9d, 0x5c, 0x1e, 0xd4, 0x5b, 0x9a, 0x1b, 0xdd, 0xdc, 0x94, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00,
        0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6,
        0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8,
        0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11,
        0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89,
        0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37,
        0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81,
        0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c,
        0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc,
        0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, 0xe0, 0x06, 0xe4, 0x20,
        0x0e, 0xe7, 0xe0, 0x06, 0xf6, 0x10, 0x0e, 0xf2, 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x16, 0x30, 0x0d, 0x97,
        0xef, 0x3c, 0xfe, 0xe2, 0x00, 0x83, 0xd8, 0x3c, 0xd4, 0xe4, 0x23, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00,
        0x47, 0x25, 0xfd, 0x0c, 0x80, 0x34, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x34, 0xa5, 0x50, 0x08,
        0x33, 0x00, 0x45, 0x40, 0x54, 0x04, 0x74, 0x63, 0x04, 0x20, 0x08, 0x82, 0xf8, 0x2f, 0x8c, 0x11, 0x80, 0x20, 0x08, 0xa2, 0x60, 0x30, 0x46, 0x00, 0x82, 0x20, 0x08, 0x82, 0xc1, 0x08, 0xc0, 0x18,
        0x01, 0x08, 0x82, 0x20, 0xfe, 0x01, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x50, 0x64, 0x09, 0x45, 0x3d, 0x48, 0x05, 0x98, 0x5e, 0x70, 0x65, 0xc1, 0x21, 0x1f, 0x0b, 0x12, 0xf8, 0x54,
        0xc1, 0xe8, 0x05, 0x57, 0x16, 0x28, 0xf2, 0xb1, 0xa0, 0x81, 0xcf, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x61, 0x30, 0x75, 0x1d, 0x56, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x12, 0x06,
        0x53, 0xd7, 0x65, 0xc1, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x61, 0x30, 0x75, 0xdd, 0xb3, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x12, 0x06, 0x53, 0xd7, 0x59, 0x0a, 0x02, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
    };
    static const D3D12_SHADER_BYTECODE vs_code_dxil = SHADER_BYTECODE(vs_code);

    static const BYTE ps_code_bias[] =
    {
#if 0
    Texture2D<float> T : register(t0);
    SamplerState S : register(s0);
    FeedbackTexture2D<SAMPLER_FEEDBACK_MIN_MIP> FB : register(u0);

    cbuffer Cbuf : register(b0) { float2 uv; float2 grad_x; float2 grad_y; float bias; };

    void main(float4 pos : SV_Position)
    {
            int2 ipos = int2(pos.xy);
            float2 modified_uv = uv;
            modified_uv += float(ipos.x) * grad_x;
            modified_uv += float(ipos.y) * grad_y;

            FB.WriteSamplerFeedbackBias(T, S, modified_uv, bias);
    }
#endif
        0x44, 0x58, 0x42, 0x43, 0x66, 0xc3, 0xd6, 0xe7, 0x22, 0x18, 0xe0, 0xe2, 0x1d, 0x00, 0x49, 0xff, 0x46, 0xe3, 0xdf, 0x99, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x08, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
        0x38, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74,
        0x69, 0x6f, 0x6e, 0x00, 0x4f, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0xc0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, 0x03, 0x04, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48,
        0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xfb, 0xa6, 0x99, 0xeb, 0x75, 0xe8, 0x26, 0xd9, 0xc6, 0x7d, 0xb8, 0xd8, 0x29, 0xc6, 0x61, 0x44, 0x58, 0x49, 0x4c, 0xdc, 0x06, 0x00, 0x00,
        0x65, 0x00, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x05, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xc4, 0x06, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00,
        0xae, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c,
        0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20,
        0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00,
        0x08, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x6d, 0x30, 0x86, 0xff, 0xff, 0xff, 0xff, 0x1f,
        0x00, 0x09, 0xa8, 0x00, 0x49, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00,
        0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c, 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x78, 0x23, 0x00,
        0x25, 0x00, 0x14, 0x66, 0x00, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x29, 0xc6, 0x20, 0x84, 0x14, 0x42, 0x86, 0xca, 0x3d, 0xc3, 0xe5, 0x4f, 0xd8, 0x43, 0x48, 0x7e, 0x08, 0x34, 0xc3, 0x42, 0xa0,
        0x00, 0x95, 0x05, 0x90, 0x94, 0xd2, 0x18, 0x63, 0x8c, 0x41, 0xea, 0xa8, 0xe1, 0xf2, 0x27, 0xec, 0x21, 0x24, 0x9f, 0xdb, 0xa8, 0x62, 0x25, 0x26, 0xbf, 0xb8, 0x6d, 0x44, 0x8c, 0x31, 0x46, 0x21,
        0x18, 0x49, 0x84, 0xda, 0x1c, 0x41, 0x50, 0x8c, 0x44, 0x0a, 0x21, 0x8f, 0xe0, 0x40, 0xc0, 0x4c, 0x61, 0x30, 0x0e, 0xec, 0x10, 0x0e, 0xf3, 0x30, 0x0f, 0x6e, 0x40, 0x0b, 0xe5, 0x80, 0x0f, 0xf4,
        0x50, 0x0f, 0xf2, 0x50, 0x0e, 0x72, 0x40, 0x0a, 0x7c, 0x60, 0x0e, 0xec, 0xf0, 0x0e, 0xe1, 0x40, 0x0f, 0x7e, 0xa0, 0x07, 0x7a, 0xd0, 0x0e, 0xe9, 0x00, 0x0f, 0xf3, 0xf0, 0x0b, 0xf4, 0x90, 0x0f,
        0xf0, 0x50, 0x0e, 0x28, 0x20, 0x33, 0x59, 0xe3, 0xc0, 0x0e, 0xe1, 0x30, 0x0f, 0xf3, 0xe0, 0x06, 0xb4, 0x50, 0x0e, 0xf8, 0x40, 0x0f, 0xf5, 0x20, 0x0f, 0xe5, 0x20, 0x07, 0xa4, 0xc0, 0x07, 0xe6,
        0xc0, 0x0e, 0xef, 0x10, 0x0e, 0xf4, 0xe0, 0x07, 0x48, 0x18, 0x93, 0xe8, 0x4c, 0xda, 0x38, 0xb0, 0x43, 0x38, 0xcc, 0xc3, 0x3c, 0xb8, 0x81, 0x29, 0x94, 0x43, 0x39, 0x90, 0x83, 0x38, 0x84, 0xc3,
        0x38, 0xac, 0x03, 0x2d, 0x94, 0x03, 0x3e, 0xd0, 0x43, 0x3d, 0xc8, 0x43, 0x39, 0xc8, 0x01, 0x29, 0xf0, 0x01, 0x1c, 0xf8, 0x01, 0x0a, 0x08, 0xd9, 0x61, 0x04, 0x61, 0x38, 0x82, 0x0b, 0xa8, 0x02,
        0x11, 0x18, 0xe3, 0x41, 0xf9, 0x26, 0x69, 0x8a, 0x28, 0x61, 0xf2, 0x59, 0x80, 0x79, 0x16, 0x22, 0x62, 0x27, 0x60, 0x22, 0x50, 0x40, 0x68, 0xa7, 0x00, 0x01, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0,
        0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07,
        0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0,
        0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d,
        0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07,
        0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x79, 0x14, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x34, 0x40, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, 0x81, 0x80, 0x00, 0x18,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0b, 0x04, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x22,
        0x25, 0x50, 0x0a, 0xe5, 0x50, 0x0c, 0x23, 0x00, 0x45, 0x50, 0x12, 0x25, 0x52, 0x38, 0x65, 0x40, 0xa5, 0x24, 0xca, 0xa0, 0x10, 0x46, 0x00, 0xe8, 0x8d, 0x00, 0x50, 0x9d, 0x01, 0xa0, 0x3b, 0x03,
        0x40, 0x7a, 0x06, 0x80, 0xf8, 0x0c, 0x00, 0xf5, 0xb1, 0x04, 0x02, 0x00, 0x79, 0x18, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec,
        0xed, 0x4d, 0x0c, 0x24, 0xc6, 0xe5, 0xc6, 0x45, 0x46, 0x26, 0x46, 0xc6, 0x85, 0x06, 0x06, 0x04, 0xa5, 0x0c, 0x86, 0x66, 0xc6, 0x8c, 0x26, 0x2c, 0x46, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x88,
        0x62, 0x82, 0x40, 0x18, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x10, 0xc7, 0x06, 0x61, 0x30, 0x28, 0xc0, 0xcd, 0x4d, 0x10, 0x08, 0x64, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x81, 0x48, 0x26, 0x08, 0x15, 0x45,
        0x60, 0x82, 0x40, 0x28, 0x13, 0x04, 0x62, 0xd9, 0x20, 0x2c, 0xcf, 0x86, 0x64, 0x61, 0x9a, 0x65, 0x19, 0x9c, 0x05, 0xda, 0x10, 0x44, 0x13, 0x84, 0xab, 0x9a, 0x20, 0x10, 0xcc, 0x04, 0xe1, 0x99,
        0x36, 0x08, 0xce, 0xb2, 0x61, 0x59, 0xa6, 0x66, 0x59, 0x06, 0xaa, 0xaa, 0x2a, 0x6b, 0x43, 0x70, 0x4d, 0x10, 0x34, 0x6b, 0x82, 0x40, 0x34, 0x1b, 0x90, 0x25, 0x6b, 0x96, 0x65, 0xd0, 0x80, 0x0d,
        0xc1, 0x36, 0x41, 0xe0, 0xae, 0x0d, 0xc8, 0xd2, 0x35, 0xcb, 0x32, 0x2c, 0xc0, 0x86, 0xc0, 0xdb, 0x40, 0x48, 0x18, 0xf7, 0x4d, 0x10, 0x3a, 0x6c, 0x43, 0x10, 0x06, 0x13, 0x04, 0x01, 0x20, 0xd1,
        0x16, 0x96, 0xe6, 0xc6, 0x65, 0xca, 0xea, 0x0b, 0xea, 0x6d, 0x2e, 0x8d, 0x2e, 0xed, 0xcd, 0x6d, 0x82, 0x50, 0x3c, 0x13, 0x84, 0x02, 0xda, 0x10, 0x2c, 0x13, 0x84, 0x22, 0x9a, 0x20, 0x14, 0xd2,
        0x04, 0x81, 0x70, 0x36, 0x08, 0x6b, 0xb0, 0x06, 0x1b, 0x96, 0xa5, 0x0c, 0xcc, 0xe0, 0x0c, 0xd0, 0x20, 0x0d, 0x86, 0x34, 0x58, 0xd4, 0x80, 0x0d, 0x36, 0x04, 0x6d, 0xb0, 0x61, 0x70, 0x03, 0x00,
        0xd8, 0x50, 0x8c, 0x01, 0x19, 0xbc, 0x01, 0x18, 0x00, 0x55, 0xd8, 0xd8, 0xec, 0xda, 0x5c, 0xd2, 0xc8, 0xca, 0xdc, 0xe8, 0xa6, 0x04, 0x41, 0x15, 0x32, 0x3c, 0x17, 0xbb, 0x32, 0xb9, 0xb9, 0xb4,
        0x37, 0xb7, 0x29, 0x01, 0xd1, 0x84, 0x0c, 0xcf, 0xc5, 0x2e, 0x8c, 0xcd, 0xae, 0x4c, 0x6e, 0x4a, 0x60, 0xd4, 0x21, 0xc3, 0x73, 0x99, 0x43, 0x0b, 0x23, 0x2b, 0x93, 0x6b, 0x7a, 0x23, 0x2b, 0x63,
        0x9b, 0x12, 0x24, 0x65, 0xc8, 0xf0, 0x5c, 0xe4, 0xca, 0xe6, 0xde, 0xea, 0xe4, 0xc6, 0xca, 0xe6, 0xa6, 0x04, 0x5f, 0x1d, 0x32, 0x3c, 0x17, 0xbb, 0xb4, 0xb2, 0xbb, 0x24, 0xb2, 0x29, 0xba, 0x30,
        0xba, 0xb2, 0x29, 0x41, 0x18, 0xd4, 0x21, 0xc3, 0x73, 0x29, 0x73, 0xa3, 0x93, 0xcb, 0x83, 0x7a, 0x4b, 0x73, 0xa3, 0x9b, 0x9b, 0x12, 0xbc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00,
        0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6,
        0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8,
        0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11,
        0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89,
        0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37,
        0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81,
        0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c,
        0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc,
        0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, 0xe0, 0x06, 0xe4, 0x20,
        0x0e, 0xe7, 0xe0, 0x06, 0xf6, 0x10, 0x0e, 0xf2, 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x36, 0xb0, 0x0d, 0x97,
        0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, 0x41, 0x44, 0xa5, 0x03, 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, 0x6d, 0x04, 0xd2, 0x70, 0xf9, 0xce, 0xe3, 0x0b, 0x11, 0x01, 0x4c, 0x44, 0x08, 0x34,
        0xc3, 0x42, 0x58, 0xc0, 0x34, 0x5c, 0xbe, 0xf3, 0xf8, 0x8b, 0x03, 0x0c, 0x62, 0xf3, 0x50, 0x93, 0x5f, 0xdc, 0xb6, 0x09, 0x78, 0xc3, 0xe5, 0x3b, 0x8f, 0x6f, 0x45, 0xc8, 0x44, 0xb0, 0x00, 0xf3,
        0x2c, 0x44, 0xf4, 0x11, 0xc4, 0x10, 0x00, 0x82, 0xb2, 0x21, 0x80, 0x64, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c,
        0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x54, 0x8a, 0x80, 0x48, 0xc9, 0x95, 0x5d, 0x21, 0xcc, 0x00, 0x94, 0xb7, 0x00, 0x95, 0x12, 0xa0, 0x31, 0x03, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00,
        0x82, 0x60, 0x00, 0x75, 0x87, 0x80, 0x61, 0xce, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x40, 0x1e, 0x02, 0x65, 0xd9, 0x33, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0xd0, 0x97, 0x4c, 0x9a, 0x06, 0x8d,
        0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x04, 0x06, 0xca, 0xb2, 0x6d, 0xd1, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x64, 0x90, 0x70, 0xdc, 0x84, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0x51,
        0x06, 0x4a, 0xd7, 0x1d, 0xc9, 0x09, 0x84, 0x4e, 0x20, 0x34, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x8d, 0x19, 0x38, 0x05, 0x18, 0x8c, 0x26, 0x04, 0xc0, 0x68, 0x82, 0x10, 0x5c, 0x31, 0x6c, 0x34,
        0x81, 0x10, 0x46, 0x13, 0x8a, 0xc1, 0x84, 0x41, 0x3e, 0x26, 0x10, 0xf2, 0x31, 0xe1, 0x80, 0x8f, 0x09, 0x07, 0x7c, 0x6e, 0x19, 0x36, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x4d, 0x1c, 0x64, 0xd0,
        0x1b, 0x8c, 0x26, 0x04, 0xc0, 0x68, 0x82, 0x10, 0x98, 0x40, 0xc8, 0xc7, 0x84, 0x42, 0x3e, 0x86, 0x08, 0xf0, 0x31, 0x44, 0x80, 0xcf, 0x88, 0xc1, 0x01, 0x80, 0x20, 0x18, 0x34, 0x78, 0x00, 0x06,
        0x97, 0x1d, 0x8c, 0x26, 0x04, 0xc2, 0x88, 0x81, 0x03, 0x80, 0x20, 0x18, 0x28, 0x7b, 0xf0, 0x71, 0x9b, 0x46, 0x0c, 0x5d, 0x17, 0x74, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
    };
    static const D3D12_SHADER_BYTECODE ps_code_bias_dxil = SHADER_BYTECODE(ps_code_bias);

#define TEX_WIDTH 2048u
#define TEX_HEIGHT 2048u
#define MIP_REGION_WIDTH 64u /* MIP_REGION_SIZE of 32 breaks on NV. Seems like it's part of the reserved set of mip region sizes in the NV Vulkan extension ... :') */
#define MIP_REGION_HEIGHT 64u
#define FEEDBACK_WIDTH (TEX_WIDTH / MIP_REGION_WIDTH)
#define FEEDBACK_HEIGHT (TEX_HEIGHT / MIP_REGION_HEIGHT)
#define TEX_MIP_LEVELS 3
#define E (1.0f / 128.0f)

    const struct test
    {
        float coord[2];
        float grad_x[2];
        float grad_y[2];
        float bias;
        unsigned expected_regions[3];
        bool exact_nv;
        bool exact_intel;
    } tests[] = {
        /* Sample a little left of the texel center of bottom-right texel in the mip region to avoid 0 weight scenario which is not well defined
         * (can trigger use or not, vkd3d-proton is conservative here but hardware tends to not be). */
        { { MIP_REGION_WIDTH - 0.5f - E, MIP_REGION_HEIGHT - 0.5f - E }, { 1, 0 }, { 0, 1 }, 0, { 1, 0, 0 }, true, true },
        { { MIP_REGION_WIDTH - 0.5f - E, MIP_REGION_HEIGHT - 0.5f - E }, { 1, 0 }, { 0, 1 }, 1.0f / 512.0f, { 1, 0, 0 }, true, true },
        /* Tri-linear aniso is out of spec on most implementations. They try really hard to snap to integer LOD.
         * Use a larger LOD bias than we should need to trigger it.
         * Also shift the texel a bit to account for our conservative aniso extent in vkd3d-proton. */
        { { MIP_REGION_WIDTH - 1.5f - E, MIP_REGION_HEIGHT - 1.5f - E }, { 1, 0 }, { 0, 1 }, 80.0f / 256.0f, { 1, 1, 0 }, true, true },
        /* Test different square rotations of gradient. */
        { { MIP_REGION_WIDTH - 0.5f - E, MIP_REGION_HEIGHT - 0.5f - E }, { 2, 0 }, { 0, 1 }, 0, { 2, 0, 0 }, true, true },
        { { MIP_REGION_WIDTH - 0.5f - E, MIP_REGION_HEIGHT - 0.5f - E }, { 1, 0 }, { 0, 2 }, 0, { 2, 0, 0 }, true, true },
        { { MIP_REGION_WIDTH - 0.5f - E, MIP_REGION_HEIGHT - 0.5f - E }, { 0, 2 }, { 1, 0 }, 0, { 2, 0, 0 }, true, true },
        { { MIP_REGION_WIDTH - 0.5f - E, MIP_REGION_HEIGHT - 0.5f - E }, { 0, 1 }, { 2, 0 }, 0, { 2, 0, 0 }, true, true },

        /* Test diagonal gradients. Study how LOD is computed. Vulkan is very fuzzy when it comes to how LOD is computed, only giving a lower and upper LOD bound.
         * D3D11 functional spec seems to mandate max(length(ddx), length(ddy)). Verify this. AMD seems to be accurate to spec, but not NV. */
#define SQRT_1_2 0.70710678118f

#define DECL_ROTATED(D, B, lod1) \
        { { MIP_REGION_WIDTH - 0.5f - E, MIP_REGION_HEIGHT - 0.5f - E }, { (D), (D) }, { -(D), (D) }, B, { 1, lod1 ? 1 : 0, 0 }, true, true }, \
        { { MIP_REGION_WIDTH - 0.5f - E, MIP_REGION_HEIGHT - 0.5f - E }, { -(D), (D) }, { -(D), -(D) }, B, { 1, lod1 ? 1 : 0, 0 }, true, true }, \
        { { MIP_REGION_WIDTH - 0.5f - E, MIP_REGION_HEIGHT - 0.5f - E }, { (D), -(D) }, { -(D), -(D) }, B, { 1, lod1 ? 1 : 0, 0 }, true, true }, \
        { { MIP_REGION_WIDTH - 0.5f - E, MIP_REGION_HEIGHT - 0.5f - E }, { (D), (D) }, { (D), -(D) }, B, { 1, lod1 ? 1 : 0, 0 }, true, true }

        DECL_ROTATED(SQRT_1_2, 0.0f, false),
        DECL_ROTATED(SQRT_1_2, 0.4f, true), /* Should compute LOD > 0 and trigger tri-linear. */

        /* Study boundary condition for aniso and filtering. Boundary seems to be +/- 0.5 * gradient, which fits nicely with bilinear being gradient = 1.
         * Test this assumption exhaustively for all integer aniso factors and some fractional values.
         * NV does not seem to use the Vulkan sampling pattern here ... The extent can widen depending on POT factors apparently.
         * Trying to reverse the exact method is futile, but this conservative estimate should be fine.
         * It's okay if vkd3d-proton is more conservative than hardware. (AMD is completely messed up here and will write neighbor mip regions.) */
#define CONSERVATIVE_ANISO_EXTENT(rate, bias) (0.5f * exp2f(ceilf(log2f(rate)))) * exp2f(bias)
#define RATE_IS_POT(rate) (exp2f(ceilf(log2f(rate))) == (rate))
#define DECL_ANISO(rate) \
        { { MIP_REGION_WIDTH - CONSERVATIVE_ANISO_EXTENT(rate, 0) - E, MIP_REGION_HEIGHT - 0.5f - E }, { rate, 0 }, { 0, 1 }, 0, { 1, 0, 0 }, RATE_IS_POT(rate), RATE_IS_POT(rate) }, \
        { { MIP_REGION_WIDTH - CONSERVATIVE_ANISO_EXTENT(rate, 0) + E, MIP_REGION_HEIGHT - 0.5f - E }, { rate, 0 }, { 0, 1 }, 0, { 2, 0, 0 }, RATE_IS_POT(rate), RATE_IS_POT(rate) }

        DECL_ANISO(1), DECL_ANISO(2), DECL_ANISO(3), DECL_ANISO(4), DECL_ANISO(5), DECL_ANISO(6), DECL_ANISO(7), DECL_ANISO(8),
        DECL_ANISO(9), DECL_ANISO(10), DECL_ANISO(11), DECL_ANISO(12), DECL_ANISO(13), DECL_ANISO(14), DECL_ANISO(15), DECL_ANISO(16),
        DECL_ANISO(1.5f), DECL_ANISO(2.5f), DECL_ANISO(3.5f), DECL_ANISO(4.5f), DECL_ANISO(5.5f), DECL_ANISO(6.5f), DECL_ANISO(7.5f), DECL_ANISO(8.5f),
        DECL_ANISO(9.5f), DECL_ANISO(10.5f), DECL_ANISO(11.5f), DECL_ANISO(12.5f), DECL_ANISO(13.5f), DECL_ANISO(14.5f), DECL_ANISO(15.5f),

#define DECL_ANISO_LOD1(rate) \
        { { 2 * MIP_REGION_WIDTH - CONSERVATIVE_ANISO_EXTENT(rate, 0) - E, MIP_REGION_HEIGHT - 0.5f - E }, { rate, 0 }, { 0, 2 }, 0, { 0, 1, 0 }, RATE_IS_POT(rate), RATE_IS_POT(rate) }, \
        { { 2 * MIP_REGION_WIDTH - CONSERVATIVE_ANISO_EXTENT(rate, 0) + E, 2 * (MIP_REGION_HEIGHT - 0.5f - E) }, { rate, 0 }, { 0, 2 }, 0, { 0, 2, 0 }, RATE_IS_POT(rate), RATE_IS_POT(rate) }
        DECL_ANISO_LOD1(2), DECL_ANISO_LOD1(3), DECL_ANISO_LOD1(4), DECL_ANISO_LOD1(5), DECL_ANISO_LOD1(6), DECL_ANISO_LOD1(7), DECL_ANISO_LOD1(8),

        /* Esoteric as all hell. It seems like LOD bias will stretch out the extent! */
#undef DECL_ANISO_LOD1
#define DECL_ANISO_LOD1(rate) \
        { { 2 * MIP_REGION_WIDTH - CONSERVATIVE_ANISO_EXTENT(rate, 1) - E, MIP_REGION_HEIGHT - 0.5f - E }, { rate, 0 }, { 0, 1 }, 1, { 0, 1, 0 }, RATE_IS_POT(rate), RATE_IS_POT(rate) }, \
        { { 2 * MIP_REGION_WIDTH - CONSERVATIVE_ANISO_EXTENT(rate, 1) + E, 2 * (MIP_REGION_HEIGHT - 0.5f - E) }, { rate, 0 }, { 0, 1 }, 1, { 0, 2, 0 }, RATE_IS_POT(rate), RATE_IS_POT(rate) }
        DECL_ANISO_LOD1(2), DECL_ANISO_LOD1(3), DECL_ANISO_LOD1(4), DECL_ANISO_LOD1(5), DECL_ANISO_LOD1(6), DECL_ANISO_LOD1(7), DECL_ANISO_LOD1(8),

        /* And negative LOD bias will shrink the footprint ... */
#undef DECL_ANISO_LOD1
#define DECL_ANISO_LOD1(rate) \
        { { 2 * MIP_REGION_WIDTH - CONSERVATIVE_ANISO_EXTENT(rate, -1) - E, MIP_REGION_HEIGHT - 0.5f - E }, { rate, 0 }, { 0, 2 }, -1, { 1, 0, 0 }, RATE_IS_POT(rate), RATE_IS_POT(rate) }, \
        { { 2 * MIP_REGION_WIDTH - CONSERVATIVE_ANISO_EXTENT(rate, -1) + E, 2 * (MIP_REGION_HEIGHT - 0.5f - E) }, { rate, 0 }, { 0, 2 }, -1, { 2, 0, 0 }, RATE_IS_POT(rate), RATE_IS_POT(rate) }
        DECL_ANISO_LOD1(2), DECL_ANISO_LOD1(3), DECL_ANISO_LOD1(4), DECL_ANISO_LOD1(5), DECL_ANISO_LOD1(6), DECL_ANISO_LOD1(7), DECL_ANISO_LOD1(8),
    };

    uint8_t expected[TEX_MIP_LEVELS][FEEDBACK_HEIGHT][FEEDBACK_WIDTH];

    memset(&context_desc, 0, sizeof(context_desc));
    context_desc.no_pipeline = true;
    context_desc.no_render_target = true;
    context_desc.no_root_signature = true;
    if (!init_test_context(&context, &context_desc))
        return;

    if (FAILED(ID3D12Device_CheckFeatureSupport(context.device, D3D12_FEATURE_D3D12_OPTIONS7, &features7, sizeof(features7))) ||
        features7.SamplerFeedbackTier < D3D12_SAMPLER_FEEDBACK_TIER_0_9)
    {
        skip("Sampler feedback not supported.\n");
        destroy_test_context(&context);
        return;
    }

    hr = ID3D12Device_QueryInterface(context.device, &IID_ID3D12Device8, (void **)&device8);
    ok(SUCCEEDED(hr), "Failed to query Device8, hr #%x.\n", hr);
    hr = ID3D12GraphicsCommandList_QueryInterface(context.list, &IID_ID3D12GraphicsCommandList1, (void **)&list1);
    ok(SUCCEEDED(hr), "Failed to query GraphicsCommandList1, hr #%x.\n", hr);

    memset(&rs_desc, 0, sizeof(rs_desc));
    memset(desc_range, 0, sizeof(desc_range));
    memset(rs_param, 0, sizeof(rs_param));
    memset(&static_sampler, 0, sizeof(static_sampler));
    rs_desc.NumParameters = ARRAY_SIZE(rs_param);
    rs_desc.pParameters = rs_param;
    rs_desc.NumStaticSamplers = 1;
    rs_desc.pStaticSamplers = &static_sampler;

    static_sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
    static_sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
    static_sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
    static_sampler.Filter = D3D12_FILTER_ANISOTROPIC;
    static_sampler.MaxAnisotropy = 16;
    static_sampler.MaxLOD = 1000.0f;

    rs_param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
    rs_param[0].DescriptorTable.NumDescriptorRanges = ARRAY_SIZE(desc_range);
    rs_param[0].DescriptorTable.pDescriptorRanges = desc_range;
    desc_range[0].NumDescriptors = 1;
    desc_range[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
    desc_range[1].NumDescriptors = 1;
    desc_range[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
    desc_range[1].OffsetInDescriptorsFromTableStart = 1;
    rs_param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
    rs_param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
    rs_param[1].Constants.Num32BitValues = 7;

    create_root_signature(context.device, &rs_desc, &context.root_signature);

    init_pipeline_state_desc_dxil(&pso_desc, context.root_signature, DXGI_FORMAT_UNKNOWN, &vs_code_dxil, &ps_code_bias_dxil, NULL);
    pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
    pso_desc.DepthStencilState.DepthEnable = FALSE;
    pso_desc.DepthStencilState.StencilEnable = FALSE;
    pso_desc.DSVFormat = DXGI_FORMAT_UNKNOWN;
    hr = ID3D12Device_CreateGraphicsPipelineState(context.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&context.pipeline_state);
    ok(SUCCEEDED(hr), "Failed to create pipeline state, hr #%x.\n", hr);

    desc_heap = create_gpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2);
    desc_heap_cpu = create_cpu_descriptor_heap(context.device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);

    resource = create_default_texture2d(context.device, TEX_WIDTH, TEX_HEIGHT, 1, TEX_MIP_LEVELS, DXGI_FORMAT_R8_UNORM, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
    resolve = create_default_texture2d(context.device, FEEDBACK_WIDTH, FEEDBACK_HEIGHT, 1, TEX_MIP_LEVELS, DXGI_FORMAT_R8_UINT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_SOURCE);

    memset(&desc, 0, sizeof(desc));
    memset(&heap_props, 0, sizeof(heap_props));

    heap_props.Type = D3D12_HEAP_TYPE_DEFAULT;
    desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    desc.SampleDesc.Count = 1;
    desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
    desc.Width = TEX_WIDTH;
    desc.Height = TEX_HEIGHT;
    desc.DepthOrArraySize = 1;
    desc.MipLevels = TEX_MIP_LEVELS;
    desc.SamplerFeedbackMipRegion.Width = MIP_REGION_WIDTH;
    desc.SamplerFeedbackMipRegion.Height = MIP_REGION_HEIGHT;
    desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
    desc.Format = DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE;
    hr = ID3D12Device8_CreateCommittedResource2(device8, &heap_props, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, &desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, NULL, &IID_ID3D12Resource, (void **)&feedback);
    ok(SUCCEEDED(hr), "Failed to create resource, hr #%x.\n", hr);

    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback, ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap));
    ID3D12Device8_CreateSamplerFeedbackUnorderedAccessView(device8, resource, feedback, ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap_cpu));

    {
        D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc;
        memset(&srv_desc, 0, sizeof(srv_desc));
        srv_desc.Format = DXGI_FORMAT_R8_UNORM;
        srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
        srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
        srv_desc.Texture2D.MipLevels = TEX_MIP_LEVELS; /* Verify that the SRV itself clamps the feedback that is written. */
        ID3D12Device_CreateShaderResourceView(context.device, resource, &srv_desc, get_cpu_descriptor_handle(&context, desc_heap, 1));
    }

    for (i = 0; i < ARRAY_SIZE(tests); i++)
    {
        vkd3d_test_set_context("Test %u", i);
        memset(expected, 0, sizeof(expected));

        ID3D12GraphicsCommandList_SetDescriptorHeaps(context.list, 1, &desc_heap);

        {
            UINT zeroes[4] = { 0 }; /* Clear value is ignored. The actual clear value is opaque, but after a resolve, it should be 0xff. */
            ID3D12GraphicsCommandList_ClearUnorderedAccessViewUint(context.list,
                ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heap),
                ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(desc_heap_cpu),
                feedback, zeroes, 0, NULL);
            uav_barrier(context.list, feedback);
        }

        ID3D12GraphicsCommandList_SetGraphicsRootSignature(context.list, context.root_signature);
        ID3D12GraphicsCommandList_SetPipelineState(context.list, context.pipeline_state);
        ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(context.list, 0, ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(desc_heap));
        ID3D12GraphicsCommandList_IASetPrimitiveTopology(context.list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
        /* Test behavior with helpers. Hint: AMD kinda breaks down here ... */
        set_viewport(&vp, 0, 0, 1, 1, 0, 1);
        set_rect(&sci, 0, 0, 1, 1);
        ID3D12GraphicsCommandList_RSSetViewports(context.list, 1, &vp);
        ID3D12GraphicsCommandList_RSSetScissorRects(context.list, 1, &sci);

        {
            float normalized_coords[7] = {
                tests[i].coord[0] / TEX_WIDTH,
                tests[i].coord[1] / TEX_HEIGHT,
                tests[i].grad_x[0] / TEX_WIDTH,
                tests[i].grad_x[1] / TEX_HEIGHT,
                tests[i].grad_y[0] / TEX_WIDTH,
                tests[i].grad_y[1] / TEX_HEIGHT,
                tests[i].bias,
            };
            ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(context.list, 1, ARRAY_SIZE(normalized_coords), normalized_coords, 0);
            ID3D12GraphicsCommandList_DrawInstanced(context.list, 3, 1, 0, 0);
        }

        transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
        /* CopyResource is allowed, but not by region. */
        transition_resource_state(context.list, resolve, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RESOLVE_DEST);
        ID3D12GraphicsCommandList1_ResolveSubresourceRegion(list1, resolve, UINT_MAX, 0, 0, feedback, UINT_MAX, NULL, DXGI_FORMAT_R8_UINT, D3D12_RESOLVE_MODE_DECODE_SAMPLER_FEEDBACK);
        transition_resource_state(context.list, resolve, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
        transition_resource_state(context.list, feedback, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);

        for (j = 0; j < TEX_MIP_LEVELS; j++)
        {
            unsigned int touched_count = 0;
            unsigned int expected;

            expected = tests[i].expected_regions[j];
            get_texture_readback_with_command_list(resolve, j, &rb, context.queue, context.list);

            for (y = 0; y < (FEEDBACK_HEIGHT >> j); y++)
            {
                for (x = 0; x < (FEEDBACK_WIDTH >> j); x++)
                {
                    unsigned int value;
                    value = get_readback_uint8(&rb, x, y);
                    if (value)
                        touched_count++;
                }
            }

            if ((is_intel_windows_device(context.device) && tests[i].exact_intel) ||
                (is_nvidia_windows_device(context.device) && tests[i].exact_nv) ||
                !vkd3d_test_platform_is_windows())
            {
                ok(touched_count == expected, "Mip %u, expected %u, got %u.\n", j, expected, touched_count);
            }
            else if (!is_amd_windows_device(context.device))
            {
                /* AMD behavior is non-sensical since it checks filtering in mip region domain ... No point even testing this. */
                /* Real hardware can be tighter. */
                ok(touched_count <= expected, "Mip %u, expected less-or-equal to %u, got %u.\n", j, expected, touched_count);
            }

            release_resource_readback(&rb);
            reset_command_list(context.list, context.allocator);
        }
    }
    vkd3d_test_set_context(NULL);

    ID3D12GraphicsCommandList1_Release(list1);
    ID3D12Resource_Release(resource);
    ID3D12Resource_Release(feedback);
    ID3D12Resource_Release(resolve);
    ID3D12DescriptorHeap_Release(desc_heap);
    ID3D12DescriptorHeap_Release(desc_heap_cpu);
    ID3D12Device8_Release(device8);
    destroy_test_context(&context);
#undef TEX_WIDTH
#undef TEX_HEIGHT
#undef MIP_REGION_WIDTH
#undef MIP_REGION_HEIGHT
#undef FEEDBACK_WIDTH
#undef FEEDBACK_HEIGHT
#undef TEX_MIP_LEVELS
#undef E
}

void test_sampler_feedback_implicit_lod(void)
{
    test_sampler_feedback_implicit_lod_inner(false);
}

void test_sampler_feedback_implicit_lod_bias(void)
{
    test_sampler_feedback_implicit_lod_inner(true);
}
