mirror of
https://github.com/hedge-dev/XenosRecomp.git
synced 2025-10-30 07:12:17 +00:00
Compare commits
13 commits
cf49b058f4
...
ebfbf9de89
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebfbf9de89 | ||
|
|
13fb9fd4b9 | ||
|
|
c96ad61b71 | ||
|
|
46938a4142 | ||
|
|
253c5954cd | ||
|
|
ce5aeb3fef | ||
|
|
d6cd7ca917 | ||
|
|
f542f86c28 | ||
|
|
88196ee508 | ||
|
|
85c3c83fa7 | ||
|
|
04539fdf02 | ||
|
|
e851c0baff | ||
|
|
421e3b3e79 |
8 changed files with 972 additions and 194 deletions
|
|
@ -4,10 +4,16 @@ if (WIN32)
|
||||||
option(XENOS_RECOMP_DXIL "Generate DXIL shader cache" ON)
|
option(XENOS_RECOMP_DXIL "Generate DXIL shader cache" ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
option(XENOS_RECOMP_AIR "Generate Metal AIR shader cache" ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(SMOLV_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/smol-v/source")
|
set(SMOLV_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/smol-v/source")
|
||||||
|
|
||||||
add_executable(XenosRecomp
|
add_executable(XenosRecomp
|
||||||
constant_table.h
|
constant_table.h
|
||||||
|
air_compiler.cpp
|
||||||
|
air_compiler.h
|
||||||
dxc_compiler.cpp
|
dxc_compiler.cpp
|
||||||
dxc_compiler.h
|
dxc_compiler.h
|
||||||
main.cpp
|
main.cpp
|
||||||
|
|
@ -51,3 +57,7 @@ if (XENOS_RECOMP_DXIL)
|
||||||
target_compile_definitions(XenosRecomp PRIVATE XENOS_RECOMP_DXIL)
|
target_compile_definitions(XenosRecomp PRIVATE XENOS_RECOMP_DXIL)
|
||||||
target_link_libraries(XenosRecomp PRIVATE Microsoft::DXIL)
|
target_link_libraries(XenosRecomp PRIVATE Microsoft::DXIL)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (XENOS_RECOMP_AIR)
|
||||||
|
target_compile_definitions(XenosRecomp PRIVATE XENOS_RECOMP_AIR)
|
||||||
|
endif()
|
||||||
|
|
|
||||||
109
XenosRecomp/air_compiler.cpp
Normal file
109
XenosRecomp/air_compiler.cpp
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
#include "air_compiler.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <spawn.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
std::vector<uint8_t> AirCompiler::compile(const std::string& shaderSource) {
|
||||||
|
// First, generate AIR from shader source
|
||||||
|
std::string inputFile = ".metal";
|
||||||
|
int tmpFD = makeTemporaryFile(inputFile);
|
||||||
|
write(tmpFD, shaderSource.data(), shaderSource.size());
|
||||||
|
close(tmpFD);
|
||||||
|
|
||||||
|
std::string irFile = ".ir";
|
||||||
|
tmpFD = makeTemporaryFile(irFile);
|
||||||
|
close(tmpFD);
|
||||||
|
|
||||||
|
pid_t pid;
|
||||||
|
char* airArgv[] = { "xcrun", "-sdk", "macosx", "metal", "-o", irFile.data(), "-c", inputFile.data(), "-D__air__", "-DUNLEASHED_RECOMP", "-Wno-unused-variable", "-frecord-sources", "-gline-tables-only", nullptr };
|
||||||
|
|
||||||
|
if (posix_spawn(&pid, "/usr/bin/xcrun", nullptr, nullptr, airArgv, nullptr) != 0) {
|
||||||
|
unlink(inputFile.data());
|
||||||
|
unlink(irFile.data());
|
||||||
|
fmt::println("Failed to spawn AIR xcrun process");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if (waitpid(pid, &status, 0) == -1) {
|
||||||
|
unlink(inputFile.data());
|
||||||
|
unlink(irFile.data());
|
||||||
|
fmt::println("Failed to wait AIR xcrun process");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||||
|
unlink(inputFile.data());
|
||||||
|
unlink(irFile.data());
|
||||||
|
fmt::println("AIR xcrun exited with code {}", WEXITSTATUS(status));
|
||||||
|
fmt::println("{}", shaderSource);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink(inputFile.data());
|
||||||
|
|
||||||
|
// Now we need to turn the AIR into a .metallib
|
||||||
|
std::string libFile = ".metallib";
|
||||||
|
tmpFD = makeTemporaryFile(libFile);
|
||||||
|
close(tmpFD);
|
||||||
|
|
||||||
|
char* libArgv[] = { "xcrun", "-sdk", "macosx", "metallib", "-o", libFile.data(), irFile.data(), nullptr };
|
||||||
|
|
||||||
|
if (posix_spawn(&pid, "/usr/bin/xcrun", nullptr, nullptr, libArgv, nullptr) != 0) {
|
||||||
|
unlink(irFile.data());
|
||||||
|
unlink(libFile.data());
|
||||||
|
fmt::println("Failed to spawn .metallib xcrun process");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waitpid(pid, &status, 0) == -1) {
|
||||||
|
unlink(irFile.data());
|
||||||
|
unlink(libFile.data());
|
||||||
|
fmt::println("Failed to wait .metallib xcrun process");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||||
|
unlink(irFile.data());
|
||||||
|
unlink(libFile.data());
|
||||||
|
fmt::println(".metallib exited with code {}", WEXITSTATUS(status));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read from built .metallib
|
||||||
|
FILE* file = fopen(libFile.data(), "rb");
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
size_t fileSize = ftell(file);
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
auto data = std::vector<uint8_t>(fileSize);
|
||||||
|
fread(data.data(), 1, fileSize, file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
// Cleanup temporary files
|
||||||
|
unlink(irFile.data());
|
||||||
|
unlink(libFile.data());
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AirCompiler::makeTemporaryFile(std::string &extension) {
|
||||||
|
const std::string path = "/tmp/xenos_metal_XXXXXX";
|
||||||
|
|
||||||
|
size_t size = path.size() + extension.size() + 1;
|
||||||
|
char fullTemplate[size];
|
||||||
|
snprintf(fullTemplate, size, "%s%s", path.c_str(), extension.c_str());
|
||||||
|
|
||||||
|
int tmpFD = mkstemps(fullTemplate, extension.size());
|
||||||
|
if (tmpFD == -1) {
|
||||||
|
fmt::println("Failed to open temporary file, \"{}\"!", std::string(fullTemplate));
|
||||||
|
unlink(fullTemplate);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
extension = fullTemplate;
|
||||||
|
return tmpFD;
|
||||||
|
}
|
||||||
9
XenosRecomp/air_compiler.h
Normal file
9
XenosRecomp/air_compiler.h
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct AirCompiler
|
||||||
|
{
|
||||||
|
static std::vector<uint8_t> compile(const std::string& shaderSource);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int makeTemporaryFile(std::string& extension);
|
||||||
|
};
|
||||||
|
|
@ -34,6 +34,11 @@ IDxcBlob* DxcCompiler::compile(const std::string& shaderSource, bool compilePixe
|
||||||
target = L"-T vs_6_0";
|
target = L"-T vs_6_0";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!compileLibrary)
|
||||||
|
{
|
||||||
|
args[argCount++] = L"-E shaderMain";
|
||||||
|
}
|
||||||
|
|
||||||
args[argCount++] = target;
|
args[argCount++] = target;
|
||||||
args[argCount++] = L"-HV 2021";
|
args[argCount++] = L"-HV 2021";
|
||||||
args[argCount++] = L"-all-resources-bound";
|
args[argCount++] = L"-all-resources-bound";
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "shader_recompiler.h"
|
#include "shader_recompiler.h"
|
||||||
#include "dxc_compiler.h"
|
#include "dxc_compiler.h"
|
||||||
|
#include "air_compiler.h"
|
||||||
|
|
||||||
static std::unique_ptr<uint8_t[]> readAllBytes(const char* filePath, size_t& fileSize)
|
static std::unique_ptr<uint8_t[]> readAllBytes(const char* filePath, size_t& fileSize)
|
||||||
{
|
{
|
||||||
|
|
@ -26,6 +27,7 @@ struct RecompiledShader
|
||||||
uint8_t* data = nullptr;
|
uint8_t* data = nullptr;
|
||||||
IDxcBlob* dxil = nullptr;
|
IDxcBlob* dxil = nullptr;
|
||||||
std::vector<uint8_t> spirv;
|
std::vector<uint8_t> spirv;
|
||||||
|
std::vector<uint8_t> air;
|
||||||
uint32_t specConstantsMask = 0;
|
uint32_t specConstantsMask = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -133,6 +135,10 @@ int main(int argc, char** argv)
|
||||||
assert(*(reinterpret_cast<uint32_t *>(shader.dxil->GetBufferPointer()) + 1) != 0 && "DXIL was not signed properly!");
|
assert(*(reinterpret_cast<uint32_t *>(shader.dxil->GetBufferPointer()) + 1) != 0 && "DXIL was not signed properly!");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef XENOS_RECOMP_AIR
|
||||||
|
shader.air = AirCompiler::compile(recompiler.out);
|
||||||
|
#endif
|
||||||
|
|
||||||
IDxcBlob* spirv = dxcCompiler.compile(recompiler.out, recompiler.isPixelShader, false, true);
|
IDxcBlob* spirv = dxcCompiler.compile(recompiler.out, recompiler.isPixelShader, false, true);
|
||||||
assert(spirv != nullptr);
|
assert(spirv != nullptr);
|
||||||
|
|
||||||
|
|
@ -154,18 +160,24 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
std::vector<uint8_t> dxil;
|
std::vector<uint8_t> dxil;
|
||||||
std::vector<uint8_t> spirv;
|
std::vector<uint8_t> spirv;
|
||||||
|
std::vector<uint8_t> air;
|
||||||
|
|
||||||
for (auto& [hash, shader] : shaders)
|
for (auto& [hash, shader] : shaders)
|
||||||
{
|
{
|
||||||
f.println("\t{{ 0x{:X}, {}, {}, {}, {}, {} }},",
|
f.println("\t{{ 0x{:X}, {}, {}, {}, {}, {}, {}, {} }},",
|
||||||
hash, dxil.size(), (shader.dxil != nullptr) ? shader.dxil->GetBufferSize() : 0, spirv.size(), shader.spirv.size(), shader.specConstantsMask);
|
hash, dxil.size(), (shader.dxil != nullptr) ? shader.dxil->GetBufferSize() : 0,
|
||||||
|
spirv.size(), shader.spirv.size(), air.size(), shader.air.size(), shader.specConstantsMask);
|
||||||
|
|
||||||
if (shader.dxil != nullptr)
|
if (shader.dxil != nullptr)
|
||||||
{
|
{
|
||||||
dxil.insert(dxil.end(), reinterpret_cast<uint8_t *>(shader.dxil->GetBufferPointer()),
|
dxil.insert(dxil.end(), reinterpret_cast<uint8_t *>(shader.dxil->GetBufferPointer()),
|
||||||
reinterpret_cast<uint8_t *>(shader.dxil->GetBufferPointer()) + shader.dxil->GetBufferSize());
|
reinterpret_cast<uint8_t *>(shader.dxil->GetBufferPointer()) + shader.dxil->GetBufferSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef XENOS_RECOMP_AIR
|
||||||
|
air.insert(air.end(), shader.air.begin(), shader.air.end());
|
||||||
|
#endif
|
||||||
|
|
||||||
spirv.insert(spirv.end(), shader.spirv.begin(), shader.spirv.end());
|
spirv.insert(spirv.end(), shader.spirv.begin(), shader.spirv.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,6 +201,22 @@ int main(int argc, char** argv)
|
||||||
f.println("const size_t g_dxilCacheDecompressedSize = {};", dxil.size());
|
f.println("const size_t g_dxilCacheDecompressedSize = {};", dxil.size());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef XENOS_RECOMP_AIR
|
||||||
|
fmt::println("Compressing AIR cache...");
|
||||||
|
|
||||||
|
std::vector<uint8_t> airCompressed(ZSTD_compressBound(air.size()));
|
||||||
|
airCompressed.resize(ZSTD_compress(airCompressed.data(), airCompressed.size(), air.data(), air.size(), level));
|
||||||
|
|
||||||
|
f.print("const uint8_t g_compressedAirCache[] = {{");
|
||||||
|
|
||||||
|
for (auto data : airCompressed)
|
||||||
|
f.print("{},", data);
|
||||||
|
|
||||||
|
f.println("}};");
|
||||||
|
f.println("const size_t g_airCacheCompressedSize = {};", airCompressed.size());
|
||||||
|
f.println("const size_t g_airCacheDecompressedSize = {};", air.size());
|
||||||
|
#endif
|
||||||
|
|
||||||
fmt::println("Compressing SPIRV cache...");
|
fmt::println("Compressing SPIRV cache...");
|
||||||
|
|
||||||
std::vector<uint8_t> spirvCompressed(ZSTD_compressBound(spirv.size()));
|
std::vector<uint8_t> spirvCompressed(ZSTD_compressBound(spirv.size()));
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,11 @@
|
||||||
#define SPEC_CONSTANT_REVERSE_Z (1 << 4)
|
#define SPEC_CONSTANT_REVERSE_Z (1 << 4)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(__cplusplus) || defined(__INTELLISENSE__)
|
#if defined(__air__) || !defined(__cplusplus) || defined(__INTELLISENSE__)
|
||||||
|
|
||||||
#define FLT_MIN asfloat(0xff7fffff)
|
#ifndef __air__
|
||||||
#define FLT_MAX asfloat(0x7f7fffff)
|
#define FLT_MAX asfloat(0x7f7fffff)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __spirv__
|
#ifdef __spirv__
|
||||||
|
|
||||||
|
|
@ -28,23 +29,101 @@ struct PushConstants
|
||||||
|
|
||||||
#define g_Booleans vk::RawBufferLoad<uint>(g_PushConstants.SharedConstants + 256)
|
#define g_Booleans vk::RawBufferLoad<uint>(g_PushConstants.SharedConstants + 256)
|
||||||
#define g_SwappedTexcoords vk::RawBufferLoad<uint>(g_PushConstants.SharedConstants + 260)
|
#define g_SwappedTexcoords vk::RawBufferLoad<uint>(g_PushConstants.SharedConstants + 260)
|
||||||
#define g_AlphaThreshold vk::RawBufferLoad<float>(g_PushConstants.SharedConstants + 264)
|
#define g_HalfPixelOffset vk::RawBufferLoad<float2>(g_PushConstants.SharedConstants + 264)
|
||||||
|
#define g_AlphaThreshold vk::RawBufferLoad<float>(g_PushConstants.SharedConstants + 272)
|
||||||
|
|
||||||
[[vk::constant_id(0)]] const uint g_SpecConstants = 0;
|
[[vk::constant_id(0)]] const uint g_SpecConstants = 0;
|
||||||
|
|
||||||
#define g_SpecConstants() g_SpecConstants
|
#define g_SpecConstants() g_SpecConstants
|
||||||
|
|
||||||
|
#elif __air__
|
||||||
|
|
||||||
|
#include <metal_stdlib>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
constant uint G_SPEC_CONSTANTS [[function_constant(0)]];
|
||||||
|
constant uint G_SPEC_CONSTANTS_VAL = is_function_constant_defined(G_SPEC_CONSTANTS) ? G_SPEC_CONSTANTS : 0;
|
||||||
|
|
||||||
|
uint g_SpecConstants()
|
||||||
|
{
|
||||||
|
return G_SPEC_CONSTANTS_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PushConstants
|
||||||
|
{
|
||||||
|
ulong VertexShaderConstants;
|
||||||
|
ulong PixelShaderConstants;
|
||||||
|
ulong SharedConstants;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define g_Booleans (*(reinterpret_cast<device uint*>(g_PushConstants.SharedConstants + 256)))
|
||||||
|
#define g_SwappedTexcoords (*(reinterpret_cast<device uint*>(g_PushConstants.SharedConstants + 260)))
|
||||||
|
#define g_HalfPixelOffset (*(reinterpret_cast<device float*>(g_PushConstants.SharedConstants + 264)))
|
||||||
|
#define g_AlphaThreshold (*(reinterpret_cast<device float*>(g_PushConstants.SharedConstants + 272)))
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define DEFINE_SHARED_CONSTANTS() \
|
#define DEFINE_SHARED_CONSTANTS() \
|
||||||
uint g_Booleans : packoffset(c16.x); \
|
uint g_Booleans : packoffset(c16.x); \
|
||||||
uint g_SwappedTexcoords : packoffset(c16.y); \
|
uint g_SwappedTexcoords : packoffset(c16.y); \
|
||||||
float g_AlphaThreshold : packoffset(c16.z) \
|
float2 g_HalfPixelOffset : packoffset(c16.z); \
|
||||||
|
float g_AlphaThreshold : packoffset(c17.x);
|
||||||
|
|
||||||
uint g_SpecConstants();
|
uint g_SpecConstants();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __air__
|
||||||
|
|
||||||
|
struct Texture2DDescriptorHeap
|
||||||
|
{
|
||||||
|
array<texture2d<float>, 1> g [[id(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Texture3DDescriptorHeap
|
||||||
|
{
|
||||||
|
array<texture3d<float>, 1> g [[id(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextureCubeDescriptorHeap
|
||||||
|
{
|
||||||
|
array<texturecube<float>, 1> g [[id(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SamplerDescriptorHeap
|
||||||
|
{
|
||||||
|
array<sampler, 1> g [[id(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
uint2 getTexture2DDimensions(texture2d<float> texture)
|
||||||
|
{
|
||||||
|
return uint2(texture.get_width(), texture.get_height());
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 tfetch2D(constant Texture2DDescriptorHeap& textureHeap,
|
||||||
|
constant SamplerDescriptorHeap& samplerHeap,
|
||||||
|
uint resourceDescriptorIndex,
|
||||||
|
uint samplerDescriptorIndex,
|
||||||
|
float2 texCoord, float2 offset)
|
||||||
|
{
|
||||||
|
texture2d<float> texture = textureHeap.g[resourceDescriptorIndex];
|
||||||
|
sampler sampler = samplerHeap.g[samplerDescriptorIndex];
|
||||||
|
return texture.sample(sampler, texCoord + offset / (float2)getTexture2DDimensions(texture));
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 getWeights2D(constant Texture2DDescriptorHeap& textureHeap,
|
||||||
|
constant SamplerDescriptorHeap& samplerHeap,
|
||||||
|
uint resourceDescriptorIndex,
|
||||||
|
uint samplerDescriptorIndex,
|
||||||
|
float2 texCoord, float2 offset)
|
||||||
|
{
|
||||||
|
texture2d<float> texture = textureHeap.g[resourceDescriptorIndex];
|
||||||
|
return select(fract(texCoord * (float2)getTexture2DDimensions(texture) + offset - 0.5), 0.0, isnan(texCoord));
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
Texture2D<float4> g_Texture2DDescriptorHeap[] : register(t0, space0);
|
Texture2D<float4> g_Texture2DDescriptorHeap[] : register(t0, space0);
|
||||||
Texture3D<float4> g_Texture3DDescriptorHeap[] : register(t0, space1);
|
Texture3D<float4> g_Texture3DDescriptorHeap[] : register(t0, space1);
|
||||||
TextureCube<float4> g_TextureCubeDescriptorHeap[] : register(t0, space2);
|
TextureCube<float4> g_TextureCubeDescriptorHeap[] : register(t0, space2);
|
||||||
|
|
@ -69,6 +148,46 @@ float2 getWeights2D(uint resourceDescriptorIndex, uint samplerDescriptorIndex, f
|
||||||
return select(isnan(texCoord), 0.0, frac(texCoord * getTexture2DDimensions(texture) + offset - 0.5));
|
return select(isnan(texCoord), 0.0, frac(texCoord * getTexture2DDimensions(texture) + offset - 0.5));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __air__
|
||||||
|
#define selectWrapper(a, b, c) select(c, b, a)
|
||||||
|
#else
|
||||||
|
#define selectWrapper(a, b, c) select(a, b, c)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __air__
|
||||||
|
#define frac(X) fract(X)
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void clip(T a)
|
||||||
|
{
|
||||||
|
if (a < 0.0) {
|
||||||
|
discard_fragment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
float rcp(T a)
|
||||||
|
{
|
||||||
|
return 1.0 / a;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
float4x4 mul(T a, T b)
|
||||||
|
{
|
||||||
|
return b * a;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __air__
|
||||||
|
#define UNROLL
|
||||||
|
#define BRANCH
|
||||||
|
#else
|
||||||
|
#define UNROLL [unroll]
|
||||||
|
#define BRANCH [branch]
|
||||||
|
#endif
|
||||||
|
|
||||||
float w0(float a)
|
float w0(float a)
|
||||||
{
|
{
|
||||||
return (1.0f / 6.0f) * (a * (a * (-a + 3.0f) - 3.0f) + 1.0f);
|
return (1.0f / 6.0f) * (a * (a * (-a + 3.0f) - 3.0f) + 1.0f);
|
||||||
|
|
@ -109,6 +228,74 @@ float h1(float a)
|
||||||
return 1.0f + w3(a) / (w2(a) + w3(a)) + 0.5f;
|
return 1.0f + w3(a) / (w2(a) + w3(a)) + 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CubeMapData
|
||||||
|
{
|
||||||
|
float3 cubeMapDirections[2];
|
||||||
|
uint cubeMapIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __air__
|
||||||
|
|
||||||
|
float4 tfetch2DBicubic(constant Texture2DDescriptorHeap& textureHeap,
|
||||||
|
constant SamplerDescriptorHeap& samplerHeap,
|
||||||
|
uint resourceDescriptorIndex,
|
||||||
|
uint samplerDescriptorIndex,
|
||||||
|
float2 texCoord, float2 offset)
|
||||||
|
{
|
||||||
|
texture2d<float> texture = textureHeap.g[resourceDescriptorIndex];
|
||||||
|
sampler sampler = samplerHeap.g[samplerDescriptorIndex];
|
||||||
|
uint2 dimensions = getTexture2DDimensions(texture);
|
||||||
|
|
||||||
|
float x = texCoord.x * dimensions.x + offset.x;
|
||||||
|
float y = texCoord.y * dimensions.y + offset.y;
|
||||||
|
|
||||||
|
x -= 0.5f;
|
||||||
|
y -= 0.5f;
|
||||||
|
float px = floor(x);
|
||||||
|
float py = floor(y);
|
||||||
|
float fx = x - px;
|
||||||
|
float fy = y - py;
|
||||||
|
|
||||||
|
float g0x = g0(fx);
|
||||||
|
float g1x = g1(fx);
|
||||||
|
float h0x = h0(fx);
|
||||||
|
float h1x = h1(fx);
|
||||||
|
float h0y = h0(fy);
|
||||||
|
float h1y = h1(fy);
|
||||||
|
|
||||||
|
float4 r =
|
||||||
|
g0(fy) * (g0x * texture.sample(sampler, float2(px + h0x, py + h0y) / float2(dimensions)) +
|
||||||
|
g1x * texture.sample(sampler, float2(px + h1x, py + h0y) / float2(dimensions))) +
|
||||||
|
g1(fy) * (g0x * texture.sample(sampler, float2(px + h0x, py + h1y) / float2(dimensions)) +
|
||||||
|
g1x * texture.sample(sampler, float2(px + h1x, py + h1y) / float2(dimensions)));
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 tfetch3D(constant Texture3DDescriptorHeap& textureHeap,
|
||||||
|
constant SamplerDescriptorHeap& samplerHeap,
|
||||||
|
uint resourceDescriptorIndex,
|
||||||
|
uint samplerDescriptorIndex,
|
||||||
|
float3 texCoord)
|
||||||
|
{
|
||||||
|
texture3d<float> texture = textureHeap.g[resourceDescriptorIndex];
|
||||||
|
sampler sampler = samplerHeap.g[samplerDescriptorIndex];
|
||||||
|
return texture.sample(sampler, texCoord);
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 tfetchCube(constant TextureCubeDescriptorHeap& textureHeap,
|
||||||
|
constant SamplerDescriptorHeap& samplerHeap,
|
||||||
|
uint resourceDescriptorIndex,
|
||||||
|
uint samplerDescriptorIndex,
|
||||||
|
float3 texCoord, thread CubeMapData* cubeMapData)
|
||||||
|
{
|
||||||
|
texturecube<float> texture = textureHeap.g[resourceDescriptorIndex];
|
||||||
|
sampler sampler = samplerHeap.g[samplerDescriptorIndex];
|
||||||
|
return texture.sample(sampler, cubeMapData->cubeMapDirections[(uint)texCoord.z]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
float4 tfetch2DBicubic(uint resourceDescriptorIndex, uint samplerDescriptorIndex, float2 texCoord, float2 offset)
|
float4 tfetch2DBicubic(uint resourceDescriptorIndex, uint samplerDescriptorIndex, float2 texCoord, float2 offset)
|
||||||
{
|
{
|
||||||
Texture2D<float4> texture = g_Texture2DDescriptorHeap[resourceDescriptorIndex];
|
Texture2D<float4> texture = g_Texture2DDescriptorHeap[resourceDescriptorIndex];
|
||||||
|
|
@ -146,17 +333,13 @@ float4 tfetch3D(uint resourceDescriptorIndex, uint samplerDescriptorIndex, float
|
||||||
return g_Texture3DDescriptorHeap[resourceDescriptorIndex].Sample(g_SamplerDescriptorHeap[samplerDescriptorIndex], texCoord);
|
return g_Texture3DDescriptorHeap[resourceDescriptorIndex].Sample(g_SamplerDescriptorHeap[samplerDescriptorIndex], texCoord);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CubeMapData
|
|
||||||
{
|
|
||||||
float3 cubeMapDirections[2];
|
|
||||||
uint cubeMapIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
float4 tfetchCube(uint resourceDescriptorIndex, uint samplerDescriptorIndex, float3 texCoord, inout CubeMapData cubeMapData)
|
float4 tfetchCube(uint resourceDescriptorIndex, uint samplerDescriptorIndex, float3 texCoord, inout CubeMapData cubeMapData)
|
||||||
{
|
{
|
||||||
return g_TextureCubeDescriptorHeap[resourceDescriptorIndex].Sample(g_SamplerDescriptorHeap[samplerDescriptorIndex], cubeMapData.cubeMapDirections[texCoord.z]);
|
return g_TextureCubeDescriptorHeap[resourceDescriptorIndex].Sample(g_SamplerDescriptorHeap[samplerDescriptorIndex], cubeMapData.cubeMapDirections[texCoord.z]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
float4 tfetchR11G11B10(uint4 value)
|
float4 tfetchR11G11B10(uint4 value)
|
||||||
{
|
{
|
||||||
if (g_SpecConstants() & SPEC_CONSTANT_R11G11B10_NORMAL)
|
if (g_SpecConstants() & SPEC_CONSTANT_R11G11B10_NORMAL)
|
||||||
|
|
@ -169,7 +352,11 @@ float4 tfetchR11G11B10(uint4 value)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#ifdef __air__
|
||||||
|
return as_type<float4>(value);
|
||||||
|
#else
|
||||||
return asfloat(value);
|
return asfloat(value);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,6 +365,19 @@ float4 tfetchTexcoord(uint swappedTexcoords, float4 value, uint semanticIndex)
|
||||||
return (swappedTexcoords & (1ull << semanticIndex)) != 0 ? value.yxwz : value;
|
return (swappedTexcoords & (1ull << semanticIndex)) != 0 ? value.yxwz : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __air__
|
||||||
|
|
||||||
|
float4 cube(float4 value, thread CubeMapData* cubeMapData)
|
||||||
|
{
|
||||||
|
uint index = cubeMapData->cubeMapIndex;
|
||||||
|
cubeMapData->cubeMapDirections[index] = value.xyz;
|
||||||
|
++cubeMapData->cubeMapIndex;
|
||||||
|
|
||||||
|
return float4(0.0, 0.0, 0.0, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
float4 cube(float4 value, inout CubeMapData cubeMapData)
|
float4 cube(float4 value, inout CubeMapData cubeMapData)
|
||||||
{
|
{
|
||||||
uint index = cubeMapData.cubeMapIndex;
|
uint index = cubeMapData.cubeMapIndex;
|
||||||
|
|
@ -187,6 +387,8 @@ float4 cube(float4 value, inout CubeMapData cubeMapData)
|
||||||
return float4(0.0, 0.0, 0.0, index);
|
return float4(0.0, 0.0, 0.0, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
float4 dst(float4 src0, float4 src1)
|
float4 dst(float4 src0, float4 src1)
|
||||||
{
|
{
|
||||||
float4 dest;
|
float4 dest;
|
||||||
|
|
@ -202,15 +404,34 @@ float4 max4(float4 src0)
|
||||||
return max(max(src0.x, src0.y), max(src0.z, src0.w));
|
return max(max(src0.x, src0.y), max(src0.z, src0.w));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __air__
|
||||||
|
|
||||||
|
float2 getPixelCoord(constant Texture2DDescriptorHeap& textureHeap,
|
||||||
|
uint resourceDescriptorIndex,
|
||||||
|
float2 texCoord)
|
||||||
|
{
|
||||||
|
texture2d<float> texture = textureHeap.g[resourceDescriptorIndex];
|
||||||
|
return (float2)getTexture2DDimensions(texture) * texCoord;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
float2 getPixelCoord(uint resourceDescriptorIndex, float2 texCoord)
|
float2 getPixelCoord(uint resourceDescriptorIndex, float2 texCoord)
|
||||||
{
|
{
|
||||||
return getTexture2DDimensions(g_Texture2DDescriptorHeap[resourceDescriptorIndex]) * texCoord;
|
return getTexture2DDimensions(g_Texture2DDescriptorHeap[resourceDescriptorIndex]) * texCoord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
float computeMipLevel(float2 pixelCoord)
|
float computeMipLevel(float2 pixelCoord)
|
||||||
{
|
{
|
||||||
|
#ifdef __air__
|
||||||
|
float2 dx = dfdx(pixelCoord);
|
||||||
|
float2 dy = dfdy(pixelCoord);
|
||||||
|
#else
|
||||||
float2 dx = ddx(pixelCoord);
|
float2 dx = ddx(pixelCoord);
|
||||||
float2 dy = ddy(pixelCoord);
|
float2 dy = ddy(pixelCoord);
|
||||||
|
#endif
|
||||||
float deltaMaxSqr = max(dot(dx, dx), dot(dy, dy));
|
float deltaMaxSqr = max(dot(dx, dx), dot(dy, dy));
|
||||||
return max(0.0, 0.5 * log2(deltaMaxSqr));
|
return max(0.0, 0.5 * log2(deltaMaxSqr));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -45,7 +45,7 @@ struct ShaderRecompiler : StringBuffer
|
||||||
out += '\t';
|
out += '\t';
|
||||||
}
|
}
|
||||||
|
|
||||||
void printDstSwizzle(uint32_t dstSwizzle, bool operand);
|
uint32_t printDstSwizzle(uint32_t dstSwizzle, bool operand);
|
||||||
void printDstSwizzle01(uint32_t dstRegister, uint32_t dstSwizzle);
|
void printDstSwizzle01(uint32_t dstRegister, uint32_t dstSwizzle);
|
||||||
|
|
||||||
void recompile(const VertexFetchInstruction& instr, uint32_t address);
|
void recompile(const VertexFetchInstruction& instr, uint32_t address);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue