//=============================================================================================================================== void TextureManager::WritePNGToFile(LPCWSTR filename, ID3D11ShaderResourceView* textureSRV) { ID3D11Texture2D *textureInterface = 0; ID3D11Resource *textureResource; textureSRV->GetResource(&textureResource); textureResource->QueryInterface<ID3D11Texture2D>(&textureInterface); HRESULT result; result = SaveWICTextureToFile(mD3DSystem->GetDeviceContext(), textureInterface, GUID_ContainerFormatPng, filename); if (FAILED(result)) { ScratchImage image; result = CaptureTexture(mD3DSystem->GetDevice11(), mD3DSystem->GetDeviceContext(), textureInterface, image); if (SUCCEEDED(result)) { result = SaveToWICFile(image.GetImages(), image.GetImageCount(), WIC_FLAGS_NONE, GUID_ContainerFormatPng, filename); if (FAILED(result)) { ZShadeMessageCenter::MsgBoxError(NULL, "Failed to save PNG texture !!"); } } } SAFE_RELEASE(textureInterface); SAFE_RELEASE(textureResource); }
//========================================================================================================================= void TextureManager::WriteTGAToFile(LPCWSTR filename, ID3D11ShaderResourceView* textureSRV) { // https://directxtex.codeplex.com/wikipage?title=CaptureTexture ID3D11Texture2D *textureInterface = 0; ID3D11Resource *textureResource; textureSRV->GetResource(&textureResource); textureResource->QueryInterface<ID3D11Texture2D>(&textureInterface); HRESULT result; //ScratchImage image; ScratchImage image; result = CaptureTexture(mD3DSystem->GetDevice11(), mD3DSystem->GetDeviceContext(), textureInterface, image); if (SUCCEEDED(result)) { result = SaveToTGAFile(*image.GetImages(), filename); if (FAILED(result)) { ZShadeMessageCenter::MsgBoxError(NULL, "Failed to save TGA texture !!"); } } SAFE_RELEASE(textureInterface); SAFE_RELEASE(textureResource); }
void SaveTextureAsDDS(ID3D11Resource* texture, const wchar* filePath) { ID3D11DevicePtr device; texture->GetDevice(&device); ID3D11DeviceContextPtr context; device->GetImmediateContext(&context); ScratchImage scratchImage; DXCall(CaptureTexture(device, context, texture, scratchImage)); DXCall(SaveToDDSFile(scratchImage.GetImages(), scratchImage.GetImageCount(), scratchImage.GetMetadata(), DDS_FLAGS_FORCE_DX10_EXT, filePath)); }
//=============================================================================================================================== HRESULT TextureManager::LoadDDSTextureFromFile(LPCWSTR tex_filename, ID3D11ShaderResourceView** srv) { HRESULT hr; TexMetadata imageMetadata; ScratchImage* image = new ScratchImage(); hr = LoadFromDDSFile(tex_filename, DDS_FLAGS_NONE, &imageMetadata, *image); hr = CreateShaderResourceView(mD3DSystem->GetDevice11(), image->GetImages(), image->GetImageCount(), imageMetadata, srv); return hr; }
void SaveTextureAsPNG(ID3D11Resource* texture, const wchar* filePath) { ID3D11DevicePtr device; texture->GetDevice(&device); ID3D11DeviceContextPtr context; device->GetImmediateContext(&context); ScratchImage scratchImage; DXCall(CaptureTexture(device, context, texture, scratchImage)); DXCall(SaveToWICFile(scratchImage.GetImages(), scratchImage.GetImageCount(), WIC_FLAGS_NONE, GetWICCodec(WIC_CODEC_PNG), filePath)); }
// Executes the basic game loop. void Game::Tick() { m_timer.Tick([&]() { Update(m_timer); }); Render(); if (m_screenshot) { OutputDebugStringA("Saving screenshot...\n"); auto commandQ = m_deviceResources->GetCommandQueue(); DX::ThrowIfFailed( SaveDDSTextureToFile(commandQ, m_screenshot.Get(), L"screenshot.dds", D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_PRESENT) ); DX::ThrowIfFailed( SaveWICTextureToFile(commandQ, m_screenshot.Get(), GUID_ContainerFormatJpeg, L"screenshot.jpg", D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_PRESENT) ); ScratchImage image; DX::ThrowIfFailed(CaptureTexture(commandQ, m_screenshot.Get(), false, image, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_PRESENT)); DX::ThrowIfFailed(SaveToDDSFile(image.GetImages(), image.GetImageCount(), image.GetMetadata(), DDS_FLAGS_NONE, L"screenshot2.dds")); DX::ThrowIfFailed(SaveToWICFile(*image.GetImage(0, 0, 0), WIC_FLAGS_NONE, GUID_ContainerFormatJpeg, L"screenshot2.jpg")); m_screenshot.Reset(); } ++m_frame; }
HRESULT Decompress( const Image* cImages, size_t nimages, const TexMetadata& metadata, DXGI_FORMAT format, ScratchImage& images ) { if ( !cImages || !nimages ) return E_INVALIDARG; if ( IsCompressed(format) || IsTypeless(format) ) return E_INVALIDARG; if ( format == DXGI_FORMAT_UNKNOWN ) { // Pick a default decompressed format based on BC input format format = _DefaultDecompress( cImages[0].format ); if ( format == DXGI_FORMAT_UNKNOWN ) { // Input is not a compressed format return E_FAIL; } } else if ( !IsValid(format) ) return E_INVALIDARG; images.Release(); TexMetadata mdata2 = metadata; mdata2.format = format; HRESULT hr = images.Initialize( mdata2 ); if ( FAILED(hr) ) return hr; if ( nimages != images.GetImageCount() ) { images.Release(); return E_FAIL; } const Image* dest = images.GetImages(); if ( !dest ) { images.Release(); return E_POINTER; } for( size_t index=0; index < nimages; ++index ) { assert( dest[ index ].format == format ); const Image& src = cImages[ index ]; if ( !IsCompressed( src.format ) ) { images.Release(); return E_FAIL; } if ( src.width != dest[ index ].width || src.height != dest[ index ].height ) { images.Release(); return E_FAIL; } hr = _DecompressBC( src, dest[ index ] ); if ( FAILED(hr) ) { images.Release(); return hr; } } return S_OK; }
HRESULT Compress( const Image* srcImages, size_t nimages, const TexMetadata& metadata, DXGI_FORMAT format, DWORD compress, float alphaRef, ScratchImage& cImages ) { if ( !srcImages || !nimages ) return E_INVALIDARG; if ( !IsCompressed(format) || IsTypeless(format) ) return E_INVALIDARG; // Image size must be a multiple of 4 (degenerate cases for mipmaps are allowed) size_t width = srcImages[0].width; if ( (width % 4) != 0 ) { if ( width != 1 && width != 2 ) return E_INVALIDARG; } size_t height = srcImages[0].height; if ( (height % 4) != 0 ) { if ( height != 1 && height != 2 ) return E_INVALIDARG; } cImages.Release(); TexMetadata mdata2 = metadata; mdata2.format = format; HRESULT hr = cImages.Initialize( mdata2 ); if ( FAILED(hr) ) return hr; if ( nimages != cImages.GetImageCount() ) { cImages.Release(); return E_FAIL; } const Image* dest = cImages.GetImages(); if ( !dest ) { cImages.Release(); return E_POINTER; } for( size_t index=0; index < nimages; ++index ) { assert( dest[ index ].format == format ); const Image& src = srcImages[ index ]; height = src.height; width = src.width; if ( width != dest[ index ].width || height != dest[ index ].height ) { cImages.Release(); return E_FAIL; } bool degenerate = ((height < 4) || (width < 4)) != 0; if ( (compress & TEX_COMPRESS_PARALLEL) && !degenerate) { #ifndef _OPENMP return E_NOTIMPL; #else if ( compress & TEX_COMPRESS_PARALLEL ) { hr = _CompressBC_Parallel( src, dest[ index ], _GetBCFlags( compress ), alphaRef ); if ( FAILED(hr) ) { cImages.Release(); return hr; } } #endif // _OPENMP } else { hr = _CompressBC( src, dest[ index ], _GetBCFlags( compress ), alphaRef, degenerate ); if ( FAILED(hr) ) { cImages.Release(); return hr; } } } return S_OK; }
//------------------------------------------------------------------------------------- // Converts to/from a premultiplied alpha version of the texture (complex) //------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT DirectX::PremultiplyAlpha( const Image* srcImages, size_t nimages, const TexMetadata& metadata, DWORD flags, ScratchImage& result) { if (!srcImages || !nimages) return E_INVALIDARG; if (IsCompressed(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format) || IsTypeless(metadata.format) || !HasAlpha(metadata.format)) return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); if ((metadata.width > UINT32_MAX) || (metadata.height > UINT32_MAX)) return E_INVALIDARG; if (metadata.IsPMAlpha() != ((flags & TEX_PMALPHA_REVERSE) != 0)) return E_FAIL; TexMetadata mdata2 = metadata; mdata2.SetAlphaMode((flags & TEX_PMALPHA_REVERSE) ? TEX_ALPHA_MODE_STRAIGHT : TEX_ALPHA_MODE_PREMULTIPLIED); HRESULT hr = result.Initialize(mdata2); if (FAILED(hr)) return hr; if (nimages != result.GetImageCount()) { result.Release(); return E_FAIL; } const Image* dest = result.GetImages(); if (!dest) { result.Release(); return E_POINTER; } for (size_t index = 0; index < nimages; ++index) { const Image& src = srcImages[index]; if (src.format != metadata.format) { result.Release(); return E_FAIL; } if ((src.width > UINT32_MAX) || (src.height > UINT32_MAX)) return E_FAIL; const Image& dst = dest[index]; assert(dst.format == metadata.format); if (src.width != dst.width || src.height != dst.height) { result.Release(); return E_FAIL; } if (flags & TEX_PMALPHA_REVERSE) { hr = (flags & TEX_PMALPHA_IGNORE_SRGB) ? DemultiplyAlpha(src, dst) : DemultiplyAlphaLinear(src, flags, dst); } else { hr = (flags & TEX_PMALPHA_IGNORE_SRGB) ? PremultiplyAlpha_(src, dst) : PremultiplyAlphaLinear(src, flags, dst); } if (FAILED(hr)) { result.Release(); return hr; } } return S_OK; }
void DDEngine::ModelObject::loadGeometry(std::vector<Mesh>& meshes) { Importer importer; const aiScene* scene = importer.ReadFile(modelPath, aiProcess_Triangulate | aiProcess_ConvertToLeftHanded | aiProcess_FlipUVs | aiProcess_SortByPType | aiProcess_OptimizeMeshes | aiProcess_OptimizeGraph | aiProcess_FixInfacingNormals | aiProcess_CalcTangentSpace ); if (!scene) { Win32Utils::showMessage("Error during loading object.", importer.GetErrorString()); return; } const aiVector3D nullVec(0.0f, 0.0f, 0.0f); for (size_t i = 0; i < scene->mNumMeshes; i++) { const aiMesh* mesh = scene->mMeshes[i]; Mesh ddeMesh; for (size_t j = 0; j < mesh->mNumVertices; j++) { const aiVector3D* pos = &(mesh->mVertices[j]); const aiVector3D* nor = mesh->HasNormals() ? &(mesh->mNormals[j]) : &nullVec; const aiVector3D* tan = mesh->HasTangentsAndBitangents() ? &(mesh->mTangents[j]) : &nullVec; const aiVector3D* tex = mesh->HasTextureCoords(0) ? &(mesh->mTextureCoords[0][j]) : &nullVec; #define VB(x, y, z, u, v, nx, ny, nz, tx, ty, tz, tw) ddeMesh.VB(VertexPositionNormalTangentTexture(XMFLOAT3(x, y, z), XMFLOAT3(nx, ny, nz), XMFLOAT4(tx, ty, tz, tw), XMFLOAT2(u, v))) VB( pos->x, pos->y, pos->z, tex->x, tex->y, nor->x, nor->y, nor->z, tan->x, tan->y, tan->z, 0.0f ); ddeMesh.materialIndex = mesh->mMaterialIndex; } for (size_t j = 0; j < mesh->mNumFaces; j++) { const aiFace& face = mesh->mFaces[j]; switch (face.mNumIndices) { case 1: ddeMesh.topology = PrimitiveTopology::POINT_LIST; break; case 2: ddeMesh.topology = PrimitiveTopology::LINE_LIST; break; case 3: ddeMesh.topology = PrimitiveTopology::TRIANGLE_LIST; break; default: ddeMesh.topology = PrimitiveTopology::UNDEFINED; break; } for (size_t index = 0; index < face.mNumIndices; index++) { ddeMesh.IB(face.mIndices[index]); } } meshes.push_back(ddeMesh); } for (size_t i = 0; i < scene->mNumMaterials; i++) { const aiMaterial* material = scene->mMaterials[i]; Material ddeMaterial; ddeMaterial.index = i; if (material->GetTextureCount(aiTextureType_DIFFUSE) > 0) { aiString Path; if (material->GetTexture(aiTextureType_DIFFUSE, 0, &Path, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) { Texture tex; tex.type = Texture::TextureType::DIFFUSE; ShaderResourceView* texture = nullptr; std::string path = Path.data; std::size_t ext = path.find(".tga"); ScratchImage image; HRESULT hr = -1; std::string currentPath = FileUtils::getPath(modelPath) + "/"; tex.path = currentPath + path; if (ext != std::string::npos) { hr = LoadFromTGAFile(StringUtils::toWstring(currentPath + path).c_str(), nullptr, image); } else { texture = TextureUtils::createTexture(currentPath + path, *Ctx); } if (SUCCEEDED(hr)) { hr = CreateShaderResourceView(Ctx->device, image.GetImages(), image.GetImageCount(), image.GetMetadata(), &texture); } if (texture) { tex.texture = texture; ddeMaterial.textureArray[Texture::TextureType::DIFFUSE] = texture; ddeMaterial.textures.push_back(tex); } } } materials.push_back(ddeMaterial); } }
//------------------------------------------------------------------------------------- // rendertest bool Test04() { ComPtr<ID3D11Device> device; HRESULT hr = SetupRenderTest(device.GetAddressOf(), nullptr); if (FAILED(hr)) { printe("Failed creating device (HRESULT %08X)\n", hr); return false; } bool success = true; size_t ncount = 0; size_t npass = 0; for (size_t index = 0; index < _countof(g_TestMedia); ++index) { if (g_TestMedia[index].options & (FLAGS_YUV | FLAGS_NOT_SUPPORTED)) { // Skip video textures which need special options to render continue; } wchar_t szPath[MAX_PATH] = {}; DWORD ret = ExpandEnvironmentStringsW(g_TestMedia[index].fname, szPath, MAX_PATH); if (!ret || ret > MAX_PATH) { printe("ERROR: ExpandEnvironmentStrings FAILED\n"); return false; } #ifdef _DEBUG OutputDebugString(szPath); OutputDebugStringA("\n"); #endif wchar_t ext[_MAX_EXT]; _wsplitpath_s(szPath, nullptr, 0, nullptr, 0, nullptr, 0, ext, _MAX_EXT); TexMetadata metadata; ScratchImage image; if (_wcsicmp(ext, L".dds") == 0) { hr = LoadFromDDSFile(szPath, DDS_FLAGS_NONE, &metadata, image); } else { hr = LoadFromWICFile(szPath, WIC_FLAGS_NONE, &metadata, image); } const TexMetadata* check = &g_TestMedia[index].metadata; if (FAILED(hr)) { success = false; printe("Failed getting data from (HRESULT %08X):\n%ls\n", hr, szPath); } else if (memcmp(&metadata, check, sizeof(TexMetadata)) != 0) { success = false; printe("Metadata error in:\n%ls\n", szPath); printmeta(&metadata); printmetachk(check); } else { ComPtr<ID3D11ShaderResourceView> pSRV; hr = CreateShaderResourceView(device.Get(), image.GetImages(), image.GetImageCount(), metadata, pSRV.GetAddressOf()); if (FAILED(hr)) { success = false; printe("Failed creating SRV from (HRESULT %08X):\n%ls\n", hr, szPath); } else { print("Viewing %ls\n", szPath); RenderTest(metadata, pSRV.Get()); ++npass; } } ++ncount; } print("%zu images tested, %zu images passed ", ncount, npass); CleanupRenderTest(); return success; }
//------------------------------------------------------------------------------------- // CreateTexture bool Test02() { ComPtr<ID3D11Device> device; HRESULT hr = CreateDevice(device.GetAddressOf(), nullptr); if (FAILED(hr)) { printe("Failed creating device (HRESULT %08X)\n", hr); return false; } bool success = true; size_t ncount = 0; size_t npass = 0; for (size_t index = 0; index < _countof(g_TestMedia); ++index) { if (g_TestMedia[index].options & FLAGS_NOT_SUPPORTED) { continue; } wchar_t szPath[MAX_PATH] = {}; DWORD ret = ExpandEnvironmentStringsW(g_TestMedia[index].fname, szPath, MAX_PATH); if (!ret || ret > MAX_PATH) { printe("ERROR: ExpandEnvironmentStrings FAILED\n"); return false; } #ifdef _DEBUG OutputDebugString(szPath); OutputDebugStringA("\n"); #endif wchar_t ext[_MAX_EXT]; _wsplitpath_s(szPath, nullptr, 0, nullptr, 0, nullptr, 0, ext, _MAX_EXT); TexMetadata metadata; ScratchImage image; if (_wcsicmp(ext, L".dds") == 0) { hr = LoadFromDDSFile(szPath, DDS_FLAGS_NONE, &metadata, image); } else { hr = LoadFromWICFile(szPath, WIC_FLAGS_NONE, &metadata, image); } const TexMetadata* check = &g_TestMedia[index].metadata; if (FAILED(hr)) { success = false; printe("Failed getting data from (HRESULT %08X):\n%ls\n", hr, szPath); } else if (memcmp(&metadata, check, sizeof(TexMetadata)) != 0) { success = false; printe("Metadata error in:\n%ls\n", szPath); printmeta(&metadata); printmetachk(check); } else { if (g_TestMedia[index].options & FLAGS_YUV) { if (!IsSupportedTexture(device.Get(), metadata)) { // Can't create video textures with mips on most hardware metadata.mipLevels = 1; if (!IsSupportedTexture(device.Get(), metadata)) { print("WARNING: Format %u is not supported by this hardware\n", metadata.format); continue; } } } ComPtr<ID3D11Resource> pResource; hr = CreateTexture(device.Get(), image.GetImages(), image.GetImageCount(), metadata, pResource.GetAddressOf()); if (FAILED(hr)) { success = false; printe("Failed creating texture from (HRESULT %08X):\n%ls\n", hr, szPath); } else { hr = CreateTextureEx(device.Get(), image.GetImages(), image.GetImageCount(), metadata, D3D11_USAGE_IMMUTABLE, D3D11_BIND_SHADER_RESOURCE, 0, 0, true, pResource.ReleaseAndGetAddressOf()); if (FAILED(hr)) { success = false; printe("Failed creating texture ex from (HRESULT %08X):\n%ls\n", hr, szPath); } else { ++npass; } } } ++ncount; } print("%zu images tested, %zu images passed ", ncount, npass); return success; }
_Use_decl_annotations_ HRESULT Compress( const Image* srcImages, size_t nimages, const TexMetadata& metadata, DXGI_FORMAT format, DWORD compress, float alphaRef, ScratchImage& cImages ) { if ( !srcImages || !nimages ) return E_INVALIDARG; if ( IsCompressed(metadata.format) || !IsCompressed(format) ) return E_INVALIDARG; if ( IsTypeless(format) || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format) ) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); cImages.Release(); TexMetadata mdata2 = metadata; mdata2.format = format; HRESULT hr = cImages.Initialize( mdata2 ); if ( FAILED(hr) ) return hr; if ( nimages != cImages.GetImageCount() ) { cImages.Release(); return E_FAIL; } const Image* dest = cImages.GetImages(); if ( !dest ) { cImages.Release(); return E_POINTER; } for( size_t index=0; index < nimages; ++index ) { assert( dest[ index ].format == format ); const Image& src = srcImages[ index ]; if ( src.width != dest[ index ].width || src.height != dest[ index ].height ) { cImages.Release(); return E_FAIL; } if ( (compress & TEX_COMPRESS_PARALLEL) ) { #ifndef _OPENMP return E_NOTIMPL; #else if ( compress & TEX_COMPRESS_PARALLEL ) { hr = _CompressBC_Parallel( src, dest[ index ], _GetBCFlags( compress ), _GetSRGBFlags( compress ), alphaRef ); if ( FAILED(hr) ) { cImages.Release(); return hr; } } #endif // _OPENMP } else { hr = _CompressBC( src, dest[ index ], _GetBCFlags( compress ), _GetSRGBFlags( compress ), alphaRef ); if ( FAILED(hr) ) { cImages.Release(); return hr; } } } return S_OK; }
//------------------------------------------------------------------------------------- // Flip/rotate image (complex) //------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT FlipRotate( const Image* srcImages, size_t nimages, const TexMetadata& metadata, DWORD flags, ScratchImage& result ) { if ( !srcImages || !nimages ) return E_INVALIDARG; if ( IsCompressed( metadata.format ) ) { // We don't support flip/rotate operations on compressed images return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); } static_assert( TEX_FR_ROTATE0 == WICBitmapTransformRotate0, "TEX_FR_ROTATE0 no longer matches WIC" ); static_assert( TEX_FR_ROTATE90 == WICBitmapTransformRotate90, "TEX_FR_ROTATE90 no longer matches WIC" ); static_assert( TEX_FR_ROTATE180 == WICBitmapTransformRotate180, "TEX_FR_ROTATE180 no longer matches WIC" ); static_assert( TEX_FR_ROTATE270 == WICBitmapTransformRotate270, "TEX_FR_ROTATE270 no longer matches WIC" ); static_assert( TEX_FR_FLIP_HORIZONTAL == WICBitmapTransformFlipHorizontal, "TEX_FR_FLIP_HORIZONTAL no longer matches WIC" ); static_assert( TEX_FR_FLIP_VERTICAL == WICBitmapTransformFlipVertical, "TEX_FR_FLIP_VERTICAL no longer matches WIC" ); // Only supports 90, 180, 270, or no rotation flags... not a combination of rotation flags switch ( flags & (TEX_FR_ROTATE90|TEX_FR_ROTATE180|TEX_FR_ROTATE270) ) { case 0: case TEX_FR_ROTATE90: case TEX_FR_ROTATE180: case TEX_FR_ROTATE270: break; default: return E_INVALIDARG; } TexMetadata mdata2 = metadata; bool flipwh = false; if (flags & (TEX_FR_ROTATE90|TEX_FR_ROTATE270)) { flipwh = true; mdata2.width = metadata.height; mdata2.height = metadata.width; } HRESULT hr = result.Initialize( mdata2 ); if ( FAILED(hr) ) return hr; if ( nimages != result.GetImageCount() ) { result.Release(); return E_FAIL; } const Image* dest = result.GetImages(); if ( !dest ) { result.Release(); return E_POINTER; } WICPixelFormatGUID pfGUID; bool wicpf = _DXGIToWIC( metadata.format, pfGUID ); for( size_t index=0; index < nimages; ++index ) { const Image& src = srcImages[ index ]; if ( src.format != metadata.format ) { result.Release(); return E_FAIL; } #ifdef _AMD64_ if ( (src.width > 0xFFFFFFFF) || (src.height > 0xFFFFFFFF) ) return E_FAIL; #endif const Image& dst = dest[ index ]; assert( dst.format == metadata.format ); if ( flipwh ) { if ( src.width != dst.height || src.height != dst.width ) { result.Release(); return E_FAIL; } } else { if ( src.width != dst.width || src.height != dst.height ) { result.Release(); return E_FAIL; } } if (wicpf) { // Case 1: Source format is supported by Windows Imaging Component hr = _PerformFlipRotateUsingWIC( src, flags, pfGUID, dst ); } else { // Case 2: Source format is not supported by WIC, so we have to convert, flip/rotate, and convert back hr = _PerformFlipRotateViaF32( src, flags, dst ); } if ( FAILED(hr) ) { result.Release(); return hr; } } return S_OK; }
//------------------------------------------------------------------------------------- // CaptureTexture bool Test05() { ComPtr<ID3D11Device> device; ComPtr<ID3D11DeviceContext> context; HRESULT hr = CreateDevice(device.GetAddressOf(), context.GetAddressOf()); if (FAILED(hr)) { printe("Failed creating device (HRESULT %08X)\n", hr); return false; } bool success = true; size_t ncount = 0; size_t npass = 0; for (size_t index = 0; index < _countof(g_TestMedia); ++index) { if (g_TestMedia[index].options & FLAGS_NOT_SUPPORTED) { continue; } wchar_t szPath[MAX_PATH] = {}; DWORD ret = ExpandEnvironmentStringsW(g_TestMedia[index].fname, szPath, MAX_PATH); if (!ret || ret > MAX_PATH) { printe("ERROR: ExpandEnvironmentStrings FAILED\n"); return false; } #ifdef _DEBUG OutputDebugString(szPath); OutputDebugStringA("\n"); #endif // Form dest path wchar_t ext[_MAX_EXT]; wchar_t fname[_MAX_FNAME]; _wsplitpath_s(szPath, nullptr, 0, nullptr, 0, fname, _MAX_FNAME, ext, _MAX_EXT); wchar_t tempDir[MAX_PATH] = {}; ret = ExpandEnvironmentStringsW(TEMP_PATH L"d3d11", tempDir, MAX_PATH); if (!ret || ret > MAX_PATH) { printe("ERROR: ExpandEnvironmentStrings FAILED\n"); return false; } CreateDirectoryW(tempDir, nullptr); wchar_t szDestPath[MAX_PATH] = {}; _wmakepath_s(szDestPath, MAX_PATH, nullptr, tempDir, fname, L".dds"); TexMetadata metadata; ScratchImage image; if (_wcsicmp(ext, L".dds") == 0) { hr = LoadFromDDSFile(szPath, DDS_FLAGS_NONE, &metadata, image); } else { hr = LoadFromWICFile(szPath, WIC_FLAGS_NONE, &metadata, image); } bool forceNoMips = false; const TexMetadata* check = &g_TestMedia[index].metadata; if (FAILED(hr)) { success = false; printe("Failed getting data from (HRESULT %08X):\n%ls\n", hr, szPath); } else if (memcmp(&metadata, check, sizeof(TexMetadata)) != 0) { success = false; printe("Metadata error in:\n%ls\n", szPath); printmeta(&metadata); printmetachk(check); } else { bool pass = true; if (g_TestMedia[index].options & FLAGS_YUV) { if (!IsSupportedTexture(device.Get(), metadata)) { // Can't create video textures with mips on most hardware metadata.mipLevels = 1; forceNoMips = true; if (!IsSupportedTexture(device.Get(), metadata)) { print("WARNING: Format %u is not supported by this hardware\n", metadata.format); continue; } } } { ComPtr<ID3D11Resource> pResource; hr = CreateTexture(device.Get(), image.GetImages(), image.GetImageCount(), metadata, pResource.GetAddressOf()); if (FAILED(hr)) { success = false; printe("Failed creating texture from (HRESULT %08X):\n%ls\n", hr, szPath); } else { ScratchImage image2; hr = CaptureTexture(device.Get(), context.Get(), pResource.Get(), image2); if (FAILED(hr)) { success = false; printe("Failed capturing texture from (HRESULT %08X):\n%ls\n", hr, szPath); } else { const TexMetadata& mdata2 = image2.GetMetadata(); if (memcmp(&mdata2, &metadata, sizeof(TexMetadata)) != 0) { success = false; printe("Metadata error in:\n%ls\n", szDestPath); printmeta(&mdata2); printmetachk(check); } else if (!forceNoMips && image.GetImageCount() != image2.GetImageCount()) { success = false; printe("Image count in captured texture (%zu) doesn't match source (%zu) in:\n%ls\n", image2.GetImageCount(), image.GetImageCount(), szDestPath); } else { hr = SaveToDDSFile(image2.GetImages(), image2.GetImageCount(), image2.GetMetadata(), DDS_FLAGS_NONE, szDestPath); if (FAILED(hr)) { success = false; pass = false; printe("Failed writing DDS to (HRESULT %08X):\n%ls\n", hr, szDestPath); } if (!IsPlanar(metadata.format)) { float mse, mseV[4]; hr = ComputeMSE(*image.GetImage(0, 0, 0), *image2.GetImage(0, 0, 0), mse, mseV); if (FAILED(hr)) { success = false; pass = false; printe("Failed comparing captured image (HRESULT %08X):\n%ls\n", hr, szPath); } else if (fabs(mse) > 0.000001f) { success = false; pass = false; printe("Failed comparing captured image MSE = %f (%f %f %f %f)... 0.f:\n%ls\n", mse, mseV[0], mseV[1], mseV[2], mseV[3], szPath); } } } } } } // Staging resource tests { ComPtr<ID3D11Resource> pStaging; hr = CreateTextureEx(device.Get(), image.GetImages(), image.GetImageCount(), metadata, D3D11_USAGE_STAGING, 0, D3D11_CPU_ACCESS_READ, 0, false, pStaging.GetAddressOf()); if (FAILED(hr)) { success = false; pass = false; printe("Failed creating test staging texture (HRESULT %08X):\n%ls\n", hr, szPath); } else { ScratchImage image2; hr = CaptureTexture(device.Get(), context.Get(), pStaging.Get(), image2); if (FAILED(hr)) { success = false; printe("Failed capturing texture from staging texture (HRESULT %08X):\n%ls\n", hr, szPath); } else { const TexMetadata& mdata2 = image2.GetMetadata(); if (memcmp(&mdata2, &metadata, sizeof(TexMetadata)) != 0) { success = false; printe("Metadata error in:\n%ls\n", szDestPath); printmeta(&mdata2); printmetachk(check); } else if (!forceNoMips && image.GetImageCount() != image2.GetImageCount()) { success = false; printe("Image count in captured texture staging texture (%zu) doesn't match source (%zu) in:\n%ls\n", image2.GetImageCount(), image.GetImageCount(), szDestPath); } else { wchar_t tname[MAX_PATH] = {}; wcscpy_s(tname, fname); wcscat_s(tname, L"_staging"); wchar_t szDestPath2[MAX_PATH] = {}; _wmakepath_s(szDestPath2, MAX_PATH, nullptr, tempDir, tname, L".dds"); hr = SaveToDDSFile(image2.GetImages(), image2.GetImageCount(), image2.GetMetadata(), DDS_FLAGS_NONE, szDestPath2); if (FAILED(hr)) { success = false; pass = false; printe("Failed writing DDS to (HRESULT %08X):\n%ls\n", hr, szDestPath2); } if (!IsPlanar(metadata.format)) { float mse, mseV[4]; hr = ComputeMSE(*image.GetImage(0, 0, 0), *image2.GetImage(0, 0, 0), mse, mseV); if (FAILED(hr)) { success = false; pass = false; printe("Failed comparing captured image (HRESULT %08X):\n%ls\n", hr, szPath); } else if (fabs(mse) > 0.000001f) { success = false; pass = false; printe("Failed comparing captured image MSE = %f (%f %f %f %f)... 0.f:\n%ls\n", mse, mseV[0], mseV[1], mseV[2], mseV[3], szPath); } } } } } } // CaptureTexture of an MSAA resource is tested elsewhere if (pass) ++npass; } ++ncount; } print("%zu images tested, %zu images passed ", ncount, npass); return success; }
int WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow ) { UNREFERENCED_PARAMETER( hPrevInstance ); UNREFERENCED_PARAMETER( lpCmdLine ); if ( !*lpCmdLine ) { MessageBox( NULL, L"Usage: ddsview <filename>", L"DDSView", MB_OK | MB_ICONEXCLAMATION ); return 0; } TexMetadata mdata; HRESULT hr = GetMetadataFromDDSFile( lpCmdLine, DDS_FLAGS_NONE, mdata ); if ( FAILED(hr) ) { WCHAR buff[2048]; swprintf_s( buff, L"Failed to open texture file\n\nFilename = %ls\nHRESULT %08X", lpCmdLine, hr ); MessageBox( NULL, buff, L"DDSView", MB_OK | MB_ICONEXCLAMATION ); return 0; } if( FAILED( InitWindow( hInstance, nCmdShow, mdata ) ) ) return 0; SetWindowTextW( g_hWnd, lpCmdLine ); if( FAILED( InitDevice( mdata ) ) ) { CleanupDevice(); return 0; } if (mdata.dimension == TEX_DIMENSION_TEXTURE3D) { if ( mdata.arraySize > 1 ) { WCHAR buff[2048]; swprintf_s( buff, L"Arrays of volume textures are not supported\n\nFilename = %ls\nArray size %Iu", lpCmdLine, mdata.arraySize ); MessageBox( NULL, buff, L"DDSView", MB_OK | MB_ICONEXCLAMATION ); return 0; } g_iMaxIndex = static_cast<UINT>( mdata.depth ); } else { g_iMaxIndex = static_cast<UINT>( mdata.arraySize ); } switch( mdata.format ) { case DXGI_FORMAT_BC6H_TYPELESS: case DXGI_FORMAT_BC6H_UF16: case DXGI_FORMAT_BC6H_SF16: case DXGI_FORMAT_BC7_TYPELESS: case DXGI_FORMAT_BC7_UNORM: case DXGI_FORMAT_BC7_UNORM_SRGB: if ( g_featureLevel < D3D_FEATURE_LEVEL_11_0 ) { WCHAR buff[2048]; swprintf_s( buff, L"BC6H/BC7 requires DirectX 11 hardware\n\nFilename = %ls\nDXGI Format %d\nFeature Level %d", lpCmdLine, mdata.format, g_featureLevel ); MessageBox( NULL, buff, L"DDSView", MB_OK | MB_ICONEXCLAMATION ); return 0; } break; default: { UINT flags = 0; hr = g_pd3dDevice->CheckFormatSupport ( mdata.format, &flags ); if ( FAILED(hr) || !(flags & (D3D11_FORMAT_SUPPORT_TEXTURE1D|D3D11_FORMAT_SUPPORT_TEXTURE2D|D3D11_FORMAT_SUPPORT_TEXTURE3D)) ) { WCHAR buff[2048]; swprintf_s( buff, L"Format not supported by DirectX hardware\n\nFilename = %ls\nDXGI Format %d\nFeature Level %d\nHRESULT = %08X", lpCmdLine, mdata.format, g_featureLevel, hr ); MessageBox( NULL, buff, L"DDSView", MB_OK | MB_ICONEXCLAMATION ); return 0; } } break; } ScratchImage image; hr = LoadFromDDSFile( lpCmdLine, DDS_FLAGS_NONE, &mdata, image ); if ( FAILED(hr) ) { WCHAR buff[2048]; swprintf_s( buff, L"Failed to load texture file\n\nFilename = %ls\nHRESULT %08X", lpCmdLine, hr ); MessageBox( NULL, buff, L"DDSView", MB_OK | MB_ICONEXCLAMATION ); return 0; } // Special case to make sure Texture cubes remain arrays mdata.miscFlags &= ~TEX_MISC_TEXTURECUBE; hr = CreateShaderResourceView( g_pd3dDevice, image.GetImages(), image.GetImageCount(), mdata, &g_pSRV ); if ( FAILED(hr) ) { WCHAR buff[2048]; swprintf_s( buff, L"Failed creating texture from file\n\nFilename = %ls\nHRESULT = %08X", lpCmdLine, hr ); MessageBox( NULL, buff, L"DDSView", MB_OK | MB_ICONEXCLAMATION ); return 0; } // Main message loop MSG msg = {0}; while( WM_QUIT != msg.message ) { if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { Render(); } } CleanupDevice(); return ( int )msg.wParam; }
//------------------------------------------------------------------------------------- // Converts to a premultiplied alpha version of the texture (complex) //------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT PremultiplyAlpha( const Image* srcImages, size_t nimages, const TexMetadata& metadata, ScratchImage& result ) { if ( !srcImages || !nimages ) return E_INVALIDARG; if ( IsCompressed(metadata.format) || IsVideo(metadata.format) || IsTypeless(metadata.format) || !HasAlpha(metadata.format) ) return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); #ifdef _M_X64 if ( (metadata.width > 0xFFFFFFFF) || (metadata.height > 0xFFFFFFFF) ) return E_INVALIDARG; #endif if ( metadata.IsPMAlpha() ) { // Already premultiplied return E_FAIL; } TexMetadata mdata2 = metadata; mdata2.SetAlphaMode(TEX_ALPHA_MODE_PREMULTIPLIED); HRESULT hr = result.Initialize( mdata2 ); if ( FAILED(hr) ) return hr; if ( nimages != result.GetImageCount() ) { result.Release(); return E_FAIL; } const Image* dest = result.GetImages(); if ( !dest ) { result.Release(); return E_POINTER; } for( size_t index=0; index < nimages; ++index ) { const Image& src = srcImages[ index ]; if ( src.format != metadata.format ) { result.Release(); return E_FAIL; } #ifdef _M_X64 if ( (src.width > 0xFFFFFFFF) || (src.height > 0xFFFFFFFF) ) return E_FAIL; #endif const Image& dst = dest[ index ]; assert( dst.format == metadata.format ); if ( src.width != dst.width || src.height != dst.height ) { result.Release(); return E_FAIL; } hr = _PremultiplyAlpha( src, dst ); if ( FAILED(hr) ) { result.Release(); return hr; } } return S_OK; }