#include "stdafx.h"
#include "TextureGPUDecoder.h"

#include "..\cppkore_incl\DirectXTex\DirectXTex.h"

#if _WIN64
#if _DEBUG
#pragma comment(lib, "..\\cppkore_libs\\DirectXTex\\DirectXTex_x64d.lib")
#else
#pragma comment(lib, "..\\cppkore_libs\\DirectXTex\\DirectXTex_x64r.lib")
#endif
#else
#error DirectXTex doesn't support non x64 builds yet
#endif

#pragma comment (lib, "d3d11.lib")

namespace Assets
{
	constexpr const uint8_t VertexShader[756] = 
	{
		0x44, 0x58, 0x42, 0x43, 0x53, 0xDB, 0xC8, 0x4A, 0xBF, 0xED, 0x5D, 0x97,
		0x64, 0x25, 0x37, 0xF6, 0x62, 0x2A, 0x0D, 0x99, 0x01, 0x00, 0x00, 0x00,
		0xF4, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
		0xA0, 0x00, 0x00, 0x00, 0xD4, 0x00, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x00,
		0x58, 0x02, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x64, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x3C, 0x00, 0x00, 0x00, 0x00, 0x05, 0xFE, 0xFF, 0x00, 0x01, 0x00, 0x00,
		0x3C, 0x00, 0x00, 0x00, 0x52, 0x44, 0x31, 0x31, 0x3C, 0x00, 0x00, 0x00,
		0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
		0x24, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52,
		0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65,
		0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31,
		0x30, 0x2E, 0x31, 0x00, 0x49, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00,
		0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x56,
		0x45, 0x52, 0x54, 0x45, 0x58, 0x49, 0x44, 0x00, 0x4F, 0x53, 0x47, 0x4E,
		0x50, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
		0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
		0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
		0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x00, 0x00,
		0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00,
		0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, 0xAB, 0xAB,
		0x53, 0x48, 0x45, 0x58, 0x24, 0x01, 0x00, 0x00, 0x50, 0x00, 0x01, 0x00,
		0x49, 0x00, 0x00, 0x00, 0x6A, 0x08, 0x00, 0x01, 0x60, 0x00, 0x00, 0x04,
		0x12, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
		0x67, 0x00, 0x00, 0x04, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0x32, 0x20, 0x10, 0x00,
		0x01, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00,
		0x36, 0x00, 0x00, 0x08, 0xC2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x01, 0x00, 0x00, 0x07,
		0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x10, 0x10, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
		0x55, 0x00, 0x00, 0x07, 0x42, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x0A, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00,
		0x01, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x05, 0x32, 0x00, 0x10, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x0A, 0xC2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x06, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF,
		0x00, 0x00, 0x00, 0xBF, 0x36, 0x00, 0x00, 0x05, 0x32, 0x20, 0x10, 0x00,
		0x01, 0x00, 0x00, 0x00, 0x46, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x07, 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x2A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x10, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x22, 0x20, 0x10, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x3E, 0x00, 0x00, 0x01,
		0x53, 0x54, 0x41, 0x54, 0x94, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
		0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};

	constexpr const uint8_t PixelShader[668] = 
	{
		0x44, 0x58, 0x42, 0x43, 0x98, 0x97, 0x06, 0x35, 0x64, 0x9D, 0x54, 0x37,
		0xA3, 0xE5, 0x60, 0x58, 0x51, 0x54, 0x64, 0x6C, 0x01, 0x00, 0x00, 0x00,
		0x9C, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
		0xFC, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00,
		0x00, 0x02, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0xC0, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
		0x3C, 0x00, 0x00, 0x00, 0x00, 0x05, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x00,
		0x96, 0x00, 0x00, 0x00, 0x52, 0x44, 0x31, 0x31, 0x3C, 0x00, 0x00, 0x00,
		0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
		0x24, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x7C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00,
		0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
		0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
		0x0D, 0x00, 0x00, 0x00, 0x49, 0x6E, 0x70, 0x75, 0x74, 0x53, 0x61, 0x6D,
		0x70, 0x6C, 0x65, 0x72, 0x00, 0x49, 0x6E, 0x70, 0x75, 0x74, 0x54, 0x65,
		0x78, 0x74, 0x75, 0x72, 0x65, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73,
		0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C,
		0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70,
		0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, 0x31, 0x00, 0xAB, 0xAB,
		0x49, 0x53, 0x47, 0x4E, 0x50, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
		0x08, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x0F, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
		0x03, 0x03, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, 0x4F, 0x53, 0x49, 0x54,
		0x49, 0x4F, 0x4E, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44,
		0x00, 0xAB, 0xAB, 0xAB, 0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00,
		0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54,
		0x41, 0x52, 0x47, 0x45, 0x54, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x45, 0x58,
		0x70, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
		0x6A, 0x08, 0x00, 0x01, 0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, 0x00, 0x70, 0x10, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03,
		0x32, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03,
		0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x8B,
		0xC2, 0x00, 0x00, 0x80, 0x43, 0x55, 0x15, 0x00, 0xF2, 0x20, 0x10, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x46, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
		0x46, 0x7E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54,
		0x94, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};

	constexpr DXGI_FORMAT DefaultDecompress(DXGI_FORMAT format)
	{
		switch (format)
		{
		case DXGI_FORMAT_BC1_TYPELESS:
		case DXGI_FORMAT_BC1_UNORM:
		case DXGI_FORMAT_BC2_TYPELESS:
		case DXGI_FORMAT_BC2_UNORM:
		case DXGI_FORMAT_BC3_TYPELESS:
		case DXGI_FORMAT_BC3_UNORM:
		case DXGI_FORMAT_BC7_TYPELESS:
		case DXGI_FORMAT_BC7_UNORM:
			return DXGI_FORMAT_R8G8B8A8_UNORM;

		case DXGI_FORMAT_BC1_UNORM_SRGB:
		case DXGI_FORMAT_BC2_UNORM_SRGB:
		case DXGI_FORMAT_BC3_UNORM_SRGB:
		case DXGI_FORMAT_BC7_UNORM_SRGB:
			return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;

		case DXGI_FORMAT_BC4_TYPELESS:
		case DXGI_FORMAT_BC4_UNORM:
			return DXGI_FORMAT_R8_UNORM;

		case DXGI_FORMAT_BC4_SNORM:
			return DXGI_FORMAT_R8_SNORM;

		case DXGI_FORMAT_BC5_TYPELESS:
		case DXGI_FORMAT_BC5_UNORM:
			return DXGI_FORMAT_R8G8_UNORM;

		case DXGI_FORMAT_BC5_SNORM:
			return DXGI_FORMAT_R8G8_SNORM;

		case DXGI_FORMAT_BC6H_TYPELESS:
		case DXGI_FORMAT_BC6H_UF16:
		case DXGI_FORMAT_BC6H_SF16:
			// We could use DXGI_FORMAT_R32G32B32_FLOAT here since BC6H is always Alpha 1.0,
			// but this format is more supported by viewers
			return DXGI_FORMAT_R32G32B32A32_FLOAT;

		default:
			return DXGI_FORMAT_UNKNOWN;
		}
	}

	TextureGPUDecoder::TextureGPUDecoder()
		: _Device(nullptr), _DeviceContext(nullptr), _VertexShader(nullptr), _PixelShader(nullptr), _Sampler(nullptr), _Supported(true)
	{
	}

	TextureGPUDecoder::~TextureGPUDecoder()
	{
		this->Shutdown();
	}

	bool TextureGPUDecoder::Initialize()
	{
		if (_Device != nullptr)
			return true;
		if (!_Supported)
			return false;

		if (FAILED(D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL, D3D11_SDK_VERSION, &_Device, NULL, &_DeviceContext)))
		{
			_Supported = false;
			return false;
		}		

		if (FAILED(this->_Device->CreateVertexShader(VertexShader, sizeof(VertexShader), nullptr, &_VertexShader)))
		{
			this->Shutdown();
			return false;
		}

		if (FAILED(this->_Device->CreatePixelShader(PixelShader, sizeof(PixelShader), nullptr, &_PixelShader)))
		{
			this->Shutdown();
			return false;
		}

		CD3D11_SAMPLER_DESC SampDesc(D3D11_DEFAULT);

		if (FAILED(this->_Device->CreateSamplerState(&SampDesc, &_Sampler)))
		{
			this->Shutdown();
			return false;
		}

		return true;
	}

	HRESULT TextureGPUDecoder::Decompress(const DirectX::Image* cImages, size_t nimages, const DirectX::TexMetadata& metadata, DXGI_FORMAT format, DirectX::ScratchImage& images)
	{
		if (_Device == nullptr)
			return ERROR_DEVICE_UNREACHABLE;

		D3D11_VIEWPORT Viewport{};
		Viewport.Width = (float)metadata.width;
		Viewport.Height = (float)metadata.height;

		this->_DeviceContext->RSSetViewports(1, &Viewport);

		ID3D11Texture2D* DestinationTexture;
		ID3D11RenderTargetView* DestinationRenderTarget;

		ID3D11Texture2D* SourceTexture;
		ID3D11ShaderResourceView* SourceShaderResource;

		ID3D11Texture2D* CopyTexture;

		if (format == DXGI_FORMAT::DXGI_FORMAT_UNKNOWN)
			format = DefaultDecompress(format);

		D3D11_TEXTURE2D_DESC DestinationDesc{};
		DestinationDesc.Width = (UINT)metadata.width;
		DestinationDesc.Height = (UINT)metadata.height;
		DestinationDesc.MipLevels = 1;	// TODO: We don't care about mips, so leave it?
		DestinationDesc.ArraySize = 1;	// TODO: Set array size...
		DestinationDesc.SampleDesc.Count = 1;
		DestinationDesc.BindFlags = D3D11_BIND_FLAG::D3D11_BIND_RENDER_TARGET;
		DestinationDesc.Format = format;
		DestinationDesc.Usage = D3D11_USAGE::D3D11_USAGE_DEFAULT;

		this->_Device->CreateTexture2D(&DestinationDesc, nullptr, &DestinationTexture);

		DestinationDesc.BindFlags = 0;
		DestinationDesc.Usage = D3D11_USAGE::D3D11_USAGE_STAGING;
		DestinationDesc.CPUAccessFlags = D3D11_CPU_ACCESS_FLAG::D3D11_CPU_ACCESS_READ;

		this->_Device->CreateTexture2D(&DestinationDesc, nullptr, &CopyTexture);

		D3D11_RENDER_TARGET_VIEW_DESC RenderDesc{};
		RenderDesc.Format = DestinationDesc.Format;
		RenderDesc.ViewDimension = D3D11_RTV_DIMENSION::D3D11_RTV_DIMENSION_TEXTURE2D;

		this->_Device->CreateRenderTargetView(DestinationTexture, &RenderDesc, &DestinationRenderTarget);

		D3D11_TEXTURE2D_DESC SourceDesc{};
		SourceDesc.Width = (UINT)metadata.width;
		SourceDesc.Height = (UINT)metadata.height;
		SourceDesc.MipLevels = 1;	// TODO: We don't care about mips, so leave it?
		SourceDesc.ArraySize = 1;	// TODO: Set array size...
		SourceDesc.SampleDesc.Count = 1;
		SourceDesc.BindFlags = D3D11_BIND_FLAG::D3D11_BIND_SHADER_RESOURCE;
		SourceDesc.Format = metadata.format;
		SourceDesc.Usage = D3D11_USAGE::D3D11_USAGE_IMMUTABLE;

		D3D11_SUBRESOURCE_DATA SourceData{};
		SourceData.pSysMem = cImages->pixels;
		SourceData.SysMemPitch = (UINT)cImages->rowPitch;

		this->_Device->CreateTexture2D(&SourceDesc, &SourceData, &SourceTexture);

		D3D11_SHADER_RESOURCE_VIEW_DESC SourceShaderDesc{};
		SourceShaderDesc.Format = SourceDesc.Format;
		SourceShaderDesc.ViewDimension = D3D_SRV_DIMENSION::D3D11_SRV_DIMENSION_TEXTURE2D;
		SourceShaderDesc.Texture2D.MipLevels = 1;

		this->_Device->CreateShaderResourceView(SourceTexture, &SourceShaderDesc, &SourceShaderResource);

		this->_DeviceContext->OMSetRenderTargets(1, &DestinationRenderTarget, nullptr);
		this->_DeviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY::D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
		this->_DeviceContext->VSSetShader(this->_VertexShader, nullptr, 0);
		this->_DeviceContext->PSSetShader(this->_PixelShader, nullptr, 0);
		this->_DeviceContext->PSSetSamplers(0, 1, &this->_Sampler);
		this->_DeviceContext->PSSetShaderResources(0, 1, &SourceShaderResource);
		this->_DeviceContext->Draw(4, 0);
		this->_DeviceContext->Flush();

		this->_DeviceContext->CopyResource(CopyTexture, DestinationTexture);

		D3D11_MAPPED_SUBRESOURCE MappedResource{};

		this->_DeviceContext->Map(CopyTexture, 0, D3D11_MAP::D3D11_MAP_READ, 0, &MappedResource);

		images.Initialize2D(format, metadata.width, metadata.height, 1, 1);
		std::memcpy(images.GetPixels(), MappedResource.pData, images.GetPixelsSize());

		this->_DeviceContext->Unmap(CopyTexture, 0);

		SourceShaderResource->Release();
		SourceTexture->Release();
		DestinationRenderTarget->Release();
		CopyTexture->Release();
		DestinationTexture->Release();

		this->_DeviceContext->ClearState();
		this->_DeviceContext->Flush();

		return S_OK;
	}

	void TextureGPUDecoder::Shutdown()
	{
		if (_VertexShader != nullptr)
			_VertexShader->Release();
		if (_PixelShader != nullptr)
			_PixelShader->Release();
		if (_Sampler != nullptr)
			_Sampler->Release();
		if (_DeviceContext != nullptr)
			_DeviceContext->Release();
		if (_Device != nullptr)
			_Device->Release();

		_Device = nullptr;
		_DeviceContext = nullptr;
		_VertexShader = nullptr;
		_PixelShader = nullptr;
		_Sampler = nullptr;
	}
}