Update
This commit is contained in:
@@ -63,6 +63,8 @@ PFNGLDELETEBUFFERSPROC glDeleteBuffers;
|
||||
PFNGLBINDBUFFERPROC glBindBuffer;
|
||||
PFNGLBUFFERDATAPROC glBufferData;
|
||||
PFNGLCREATESHADERPROC glCreateShader;
|
||||
PFNGLDELETESHADERPROC glDeleteShader;
|
||||
PFNGLDELETEPROGRAMPROC glDeleteProgram;
|
||||
PFNGLSHADERSOURCEPROC glShaderSource;
|
||||
PFNGLCOMPILESHADERPROC glCompileShader;
|
||||
PFNGLGETSHADERIVPROC glGetShaderiv;
|
||||
@@ -98,6 +100,8 @@ bool ResolveGLExtensions()
|
||||
glBindBuffer = (PFNGLBINDBUFFERPROC) wglGetProcAddress("glBindBuffer");
|
||||
glBufferData = (PFNGLBUFFERDATAPROC) wglGetProcAddress("glBufferData");
|
||||
glCreateShader = (PFNGLCREATESHADERPROC) wglGetProcAddress("glCreateShader");
|
||||
glDeleteShader = (PFNGLDELETESHADERPROC) wglGetProcAddress("glDeleteShader");
|
||||
glDeleteProgram = (PFNGLDELETEPROGRAMPROC) wglGetProcAddress("glDeleteProgram");
|
||||
glShaderSource = (PFNGLSHADERSOURCEPROC) wglGetProcAddress("glShaderSource");
|
||||
glCompileShader = (PFNGLCOMPILESHADERPROC) wglGetProcAddress("glCompileShader");
|
||||
glGetShaderiv = (PFNGLGETSHADERIVPROC) wglGetProcAddress("glGetShaderiv");
|
||||
@@ -131,6 +135,8 @@ bool ResolveGLExtensions()
|
||||
&& glBindBuffer
|
||||
&& glBufferData
|
||||
&& glCreateShader
|
||||
&& glDeleteShader
|
||||
&& glDeleteProgram
|
||||
&& glShaderSource
|
||||
&& glCompileShader
|
||||
&& glGetShaderiv
|
||||
|
||||
@@ -90,6 +90,8 @@ typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
|
||||
typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
|
||||
typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
|
||||
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
|
||||
typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
|
||||
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
|
||||
@@ -134,6 +136,8 @@ extern PFNGLDELETEBUFFERSPROC glDeleteBuffers;
|
||||
extern PFNGLBINDBUFFERPROC glBindBuffer;
|
||||
extern PFNGLBUFFERDATAPROC glBufferData;
|
||||
extern PFNGLCREATESHADERPROC glCreateShader;
|
||||
extern PFNGLDELETESHADERPROC glDeleteShader;
|
||||
extern PFNGLDELETEPROGRAMPROC glDeleteProgram;
|
||||
extern PFNGLSHADERSOURCEPROC glShaderSource;
|
||||
extern PFNGLCOMPILESHADERPROC glCompileShader;
|
||||
extern PFNGLGETSHADERIVPROC glGetShaderiv;
|
||||
|
||||
@@ -210,6 +210,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
wglMakeCurrent( NULL, NULL );
|
||||
break;
|
||||
|
||||
case WM_KEYDOWN:
|
||||
if (pOpenGLComposite && (wParam == 'R' || wParam == 'r'))
|
||||
{
|
||||
pOpenGLComposite->ReloadShader();
|
||||
InvalidateRect(hWnd, NULL, FALSE);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return (DefWindowProc(hWnd, message, wParam, lParam));
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
<PrecompiledHeader />
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>dvp.lib;opengl32.lib;Glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
@@ -105,8 +106,7 @@
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /y "..\..\3rdParty\Blackmagic DeckLink SDK 16.0\Win\Samples\NVIDIA_GPUDirect\bin\$(Platform)\dvp.dll" "$(TargetDir)"
|
||||
copy /y "video_effect.frag" "$(TargetDir)"</Command>
|
||||
<Command>copy /y "..\..\3rdParty\Blackmagic DeckLink SDK 16.0\Win\Samples\NVIDIA_GPUDirect\bin\$(Platform)\dvp.dll" "$(TargetDir)"</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -122,6 +122,7 @@ copy /y "video_effect.frag" "$(TargetDir)"</Command>
|
||||
<PrecompiledHeader />
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>dvp.lib;opengl32.lib;Glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
@@ -131,8 +132,7 @@ copy /y "video_effect.frag" "$(TargetDir)"</Command>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /y "..\..\3rdParty\Blackmagic DeckLink SDK 16.0\Win\Samples\NVIDIA_GPUDirect\bin\$(Platform)\dvp.dll" "$(TargetDir)"
|
||||
copy /y "video_effect.frag" "$(TargetDir)"</Command>
|
||||
<Command>copy /y "..\..\3rdParty\Blackmagic DeckLink SDK 16.0\Win\Samples\NVIDIA_GPUDirect\bin\$(Platform)\dvp.dll" "$(TargetDir)"</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@@ -146,6 +146,7 @@ copy /y "video_effect.frag" "$(TargetDir)"</Command>
|
||||
<PrecompiledHeader />
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>dvp.lib;opengl32.lib;Glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
@@ -158,8 +159,7 @@ copy /y "video_effect.frag" "$(TargetDir)"</Command>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Message>Copy nececssary DLLs to target directory</Message>
|
||||
<Command>copy /y "..\..\3rdParty\Blackmagic DeckLink SDK 16.0\Win\Samples\NVIDIA_GPUDirect\bin\$(Platform)\dvp.dll" "$(TargetDir)"
|
||||
copy /y "video_effect.frag" "$(TargetDir)"</Command>
|
||||
<Command>copy /y "..\..\3rdParty\Blackmagic DeckLink SDK 16.0\Win\Samples\NVIDIA_GPUDirect\bin\$(Platform)\dvp.dll" "$(TargetDir)"</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -176,6 +176,7 @@ copy /y "video_effect.frag" "$(TargetDir)"</Command>
|
||||
<PrecompiledHeader />
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>dvp.lib;opengl32.lib;Glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
@@ -187,8 +188,7 @@ copy /y "video_effect.frag" "$(TargetDir)"</Command>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy /y "..\..\3rdParty\Blackmagic DeckLink SDK 16.0\Win\Samples\NVIDIA_GPUDirect\bin\$(Platform)\dvp.dll" "$(TargetDir)"
|
||||
copy /y "video_effect.frag" "$(TargetDir)"</Command>
|
||||
<Command>copy /y "..\..\3rdParty\Blackmagic DeckLink SDK 16.0\Win\Samples\NVIDIA_GPUDirect\bin\$(Platform)\dvp.dll" "$(TargetDir)"</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
@@ -218,7 +218,7 @@ copy /y "video_effect.frag" "$(TargetDir)"</Command>
|
||||
<Image Include="small.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="video_effect.frag" />
|
||||
<None Include="video_effect.slang" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="LoopThroughWithOpenGLCompositing.rc" />
|
||||
|
||||
@@ -78,4 +78,9 @@
|
||||
<Filter>DeckLink API</Filter>
|
||||
</Midl>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
<ItemGroup>
|
||||
<None Include="video_effect.slang">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -41,9 +41,11 @@
|
||||
#include "OpenGLComposite.h"
|
||||
#include "GLExtensions.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <initguid.h>
|
||||
DEFINE_GUID(IID_PinnedMemoryAllocator,
|
||||
@@ -51,7 +53,20 @@ DEFINE_GUID(IID_PinnedMemoryAllocator,
|
||||
|
||||
namespace
|
||||
{
|
||||
const char* kFragmentShaderFilename = "video_effect.frag";
|
||||
const char* kSlangShaderRelativePath = "apps/LoopThroughWithOpenGLCompositing/video_effect.slang";
|
||||
const char* kRuntimeShaderCacheDirectory = "shader_cache";
|
||||
const char* kRuntimeRawShaderFilename = "video_effect.raw.frag";
|
||||
const char* kRuntimePatchedShaderFilename = "video_effect.frag";
|
||||
const char* kVertexShaderSource =
|
||||
"#version 130\n"
|
||||
"out vec2 vTexCoord;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec2 positions[3] = vec2[3](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));\n"
|
||||
" vec2 texCoords[3] = vec2[3](vec2(0.0, 0.0), vec2(2.0, 0.0), vec2(0.0, 2.0));\n"
|
||||
" gl_Position = vec4(positions[gl_VertexID], 0.0, 1.0);\n"
|
||||
" vTexCoord = texCoords[gl_VertexID];\n"
|
||||
"}\n";
|
||||
|
||||
std::string GetExecutableDirectory()
|
||||
{
|
||||
@@ -68,6 +83,19 @@ std::string GetExecutableDirectory()
|
||||
return path.substr(0, slashIndex);
|
||||
}
|
||||
|
||||
bool ReplaceAll(std::string& text, const std::string& from, const std::string& to)
|
||||
{
|
||||
bool replaced = false;
|
||||
std::string::size_type startPos = 0;
|
||||
while ((startPos = text.find(from, startPos)) != std::string::npos)
|
||||
{
|
||||
text.replace(startPos, from.length(), to);
|
||||
startPos += to.length();
|
||||
replaced = true;
|
||||
}
|
||||
return replaced;
|
||||
}
|
||||
|
||||
void CopyErrorMessage(const std::string& message, int errorMessageSize, char* errorMessage)
|
||||
{
|
||||
if (!errorMessage || errorMessageSize <= 0)
|
||||
@@ -97,6 +125,158 @@ bool LoadTextFile(const std::string& path, std::string& contents, std::string& e
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::filesystem::path FindRepoRoot()
|
||||
{
|
||||
std::vector<std::filesystem::path> rootsToTry;
|
||||
|
||||
char currentDirBuffer[MAX_PATH] = {};
|
||||
if (GetCurrentDirectoryA(MAX_PATH, currentDirBuffer) > 0)
|
||||
rootsToTry.push_back(std::filesystem::path(currentDirBuffer));
|
||||
|
||||
std::string executableDirectory = GetExecutableDirectory();
|
||||
if (!executableDirectory.empty())
|
||||
rootsToTry.push_back(std::filesystem::path(executableDirectory));
|
||||
|
||||
for (const std::filesystem::path& startPath : rootsToTry)
|
||||
{
|
||||
std::filesystem::path candidate = startPath;
|
||||
for (int depth = 0; depth < 8 && !candidate.empty(); ++depth)
|
||||
{
|
||||
if (std::filesystem::exists(candidate / kSlangShaderRelativePath))
|
||||
return candidate;
|
||||
|
||||
candidate = candidate.parent_path();
|
||||
}
|
||||
}
|
||||
|
||||
return std::filesystem::path();
|
||||
}
|
||||
|
||||
bool FindSlangCompiler(const std::filesystem::path& repoRoot, std::filesystem::path& slangCompilerPath, std::string& error)
|
||||
{
|
||||
std::filesystem::path thirdPartyPath = repoRoot / "3rdParty";
|
||||
if (!std::filesystem::exists(thirdPartyPath))
|
||||
{
|
||||
error = "Could not locate the 3rdParty directory from the application runtime path.";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(thirdPartyPath))
|
||||
{
|
||||
if (!entry.is_directory())
|
||||
continue;
|
||||
|
||||
std::filesystem::path candidate = entry.path() / "bin" / "slangc.exe";
|
||||
if (std::filesystem::exists(candidate))
|
||||
{
|
||||
slangCompilerPath = candidate;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
error = "Could not find slangc.exe under 3rdParty.";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RunProcessAndWait(const std::string& commandLine, std::string& error)
|
||||
{
|
||||
STARTUPINFOA startupInfo = {};
|
||||
PROCESS_INFORMATION processInfo = {};
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
|
||||
std::vector<char> mutableCommandLine(commandLine.begin(), commandLine.end());
|
||||
mutableCommandLine.push_back('\0');
|
||||
|
||||
if (!CreateProcessA(NULL, mutableCommandLine.data(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo))
|
||||
{
|
||||
error = "Failed to start slangc.exe.";
|
||||
return false;
|
||||
}
|
||||
|
||||
WaitForSingleObject(processInfo.hProcess, INFINITE);
|
||||
|
||||
DWORD exitCode = 0;
|
||||
GetExitCodeProcess(processInfo.hProcess, &exitCode);
|
||||
|
||||
CloseHandle(processInfo.hThread);
|
||||
CloseHandle(processInfo.hProcess);
|
||||
|
||||
if (exitCode != 0)
|
||||
{
|
||||
error = "slangc.exe returned a non-zero exit code while compiling the runtime shader.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PatchGeneratedSlangGLSL(std::string& shaderText, std::string& error)
|
||||
{
|
||||
bool replacedVersion = ReplaceAll(shaderText, "#version 450", "#version 130");
|
||||
ReplaceAll(shaderText, "#extension GL_EXT_samplerless_texture_functions : require\n", "");
|
||||
ReplaceAll(shaderText, "layout(row_major) uniform;\n", "");
|
||||
ReplaceAll(shaderText, "layout(row_major) buffer;\n", "");
|
||||
ReplaceAll(shaderText, "layout(binding = 0)\nuniform texture2D UYVYtex_0;", "uniform sampler2D UYVYtex;");
|
||||
ReplaceAll(shaderText, "layout(location = 0)\nout vec4 entryPointParam_fragmentMain_0;\n", "");
|
||||
ReplaceAll(shaderText, "layout(location = 0)\nin vec2 input_texCoord_0;\n", "in vec2 vTexCoord;\n");
|
||||
ReplaceAll(shaderText, "UYVYtex_0", "UYVYtex");
|
||||
ReplaceAll(shaderText, "input_texCoord_0", "vTexCoord");
|
||||
ReplaceAll(shaderText, "entryPointParam_fragmentMain_0 =", "gl_FragColor =");
|
||||
|
||||
if (!replacedVersion)
|
||||
{
|
||||
error = "Generated Slang GLSL did not contain the expected version header.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuildFragmentShaderSourceFromSlang(std::string& shaderSource, std::string& error)
|
||||
{
|
||||
std::filesystem::path repoRoot = FindRepoRoot();
|
||||
if (repoRoot.empty())
|
||||
{
|
||||
error = "Could not locate the repository root to load video_effect.slang.";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::filesystem::path slangSourcePath = repoRoot / kSlangShaderRelativePath;
|
||||
if (!std::filesystem::exists(slangSourcePath))
|
||||
{
|
||||
error = "Could not find video_effect.slang.";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::filesystem::path slangCompilerPath;
|
||||
if (!FindSlangCompiler(repoRoot, slangCompilerPath, error))
|
||||
return false;
|
||||
|
||||
std::filesystem::path shaderCachePath = std::filesystem::path(GetExecutableDirectory()) / kRuntimeShaderCacheDirectory;
|
||||
std::filesystem::create_directories(shaderCachePath);
|
||||
|
||||
std::filesystem::path rawShaderPath = shaderCachePath / kRuntimeRawShaderFilename;
|
||||
std::filesystem::path patchedShaderPath = shaderCachePath / kRuntimePatchedShaderFilename;
|
||||
|
||||
std::string commandLine = "\"" + slangCompilerPath.string() + "\" \"" + slangSourcePath.string()
|
||||
+ "\" -target glsl -profile glsl_430 -entry fragmentMain -stage fragment -o \"" + rawShaderPath.string() + "\"";
|
||||
|
||||
if (!RunProcessAndWait(commandLine, error))
|
||||
return false;
|
||||
|
||||
if (!LoadTextFile(rawShaderPath.string(), shaderSource, error))
|
||||
return false;
|
||||
|
||||
if (!PatchGeneratedSlangGLSL(shaderSource, error))
|
||||
return false;
|
||||
|
||||
std::ofstream patchedShaderOutput(patchedShaderPath.string().c_str(), std::ios::binary);
|
||||
if (patchedShaderOutput)
|
||||
patchedShaderOutput << shaderSource;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
OpenGLComposite::OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC) :
|
||||
@@ -109,6 +289,10 @@ OpenGLComposite::OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC) :
|
||||
mFastTransferExtensionAvailable(false),
|
||||
mCaptureTexture(0),
|
||||
mFBOTexture(0),
|
||||
mProgram(0),
|
||||
mVertexShader(0),
|
||||
mFragmentShader(0),
|
||||
mUYVYtexUniform(-1),
|
||||
mRotateAngle(0.0f),
|
||||
mRotateAngleRate(0.0f)
|
||||
{
|
||||
@@ -164,6 +348,8 @@ OpenGLComposite::~OpenGLComposite()
|
||||
mPlayoutAllocator = NULL;
|
||||
}
|
||||
|
||||
destroyShaderProgram();
|
||||
|
||||
DeleteCriticalSection(&pMutex);
|
||||
}
|
||||
|
||||
@@ -177,7 +363,6 @@ bool OpenGLComposite::InitDeckLink()
|
||||
IDeckLinkDisplayMode* pDLDisplayMode = NULL;
|
||||
BMDDisplayMode displayMode = bmdModeHD1080p5994; // mode to use for capture and playout
|
||||
int outputFrameRowBytes;
|
||||
float fps;
|
||||
HRESULT result;
|
||||
|
||||
result = CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&pDLIterator);
|
||||
@@ -267,10 +452,7 @@ bool OpenGLComposite::InitDeckLink()
|
||||
if (! InitOpenGLState())
|
||||
goto error;
|
||||
|
||||
// Compute a rotate angle rate so box will spin at a rate independent of video mode frame rate
|
||||
pDLDisplayMode->GetFrameRate(&mFrameDuration, &mFrameTimescale);
|
||||
fps = (float)mFrameTimescale / (float)mFrameDuration;
|
||||
mRotateAngleRate = 35.0f / fps; // rotate box through 35 degrees every second
|
||||
|
||||
// Resize window to match video frame, but scale large formats down by half for viewing
|
||||
if (mFrameWidth < 1920)
|
||||
@@ -413,7 +595,7 @@ bool OpenGLComposite::InitOpenGLState()
|
||||
if (! ResolveGLExtensions())
|
||||
return false;
|
||||
|
||||
// Prepare the shader used to perform colour space conversion on the video texture
|
||||
// Prepare the runtime shader program generated from the Slang source file.
|
||||
char compilerErrorMessage[1024];
|
||||
if (! compileFragmentShader(sizeof(compilerErrorMessage), compilerErrorMessage))
|
||||
{
|
||||
@@ -421,13 +603,8 @@ bool OpenGLComposite::InitOpenGLState()
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup the scene
|
||||
glShadeModel( GL_SMOOTH ); // Enable smooth shading
|
||||
glClearColor( 0.0f, 0.0f, 0.0f, 0.5f ); // Black background
|
||||
glClearDepth( 1.0f ); // Depth buffer setup
|
||||
glEnable( GL_DEPTH_TEST ); // Enable depth testing
|
||||
glDepthFunc( GL_LEQUAL ); // Type of depth test to do
|
||||
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
if (! mFastTransferExtensionAvailable)
|
||||
{
|
||||
@@ -546,8 +723,8 @@ void OpenGLComposite::VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame, bo
|
||||
inputFrameBuffer->Release();
|
||||
}
|
||||
|
||||
// Draw the captured video frame texture onto a box, rendering to the off-screen frame buffer.
|
||||
// Read the rendered scene back from the frame buffer and schedule it for playout.
|
||||
// Render the live video texture through the runtime shader into the off-screen framebuffer.
|
||||
// Read the result back from the frame buffer and schedule it for playout.
|
||||
void OpenGLComposite::PlayoutFrameCompleted(IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult completionResult)
|
||||
{
|
||||
EnterCriticalSection(&pMutex);
|
||||
@@ -560,111 +737,9 @@ void OpenGLComposite::PlayoutFrameCompleted(IDeckLinkVideoFrame* completedFrame,
|
||||
// make GL context current in this thread
|
||||
wglMakeCurrent( hGLDC, hGLRC );
|
||||
|
||||
// Draw OpenGL scene to the off-screen frame buffer
|
||||
// Draw the effect output to the off-screen framebuffer.
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mIdFrameBuf);
|
||||
|
||||
// Setup view and projection
|
||||
GLfloat aspectRatio = (GLfloat)mFrameWidth / (GLfloat)mFrameHeight;
|
||||
glViewport (0, 0, mFrameWidth, mFrameHeight);
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadIdentity();
|
||||
gluPerspective( 45.0f, aspectRatio, 0.1f, 100.0f );
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
|
||||
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
glScalef( aspectRatio, 1.0f, 1.0f ); // Scale x for correct aspect ratio
|
||||
glTranslatef( 0.0f, 0.0f, -4.0f ); // Move into screen
|
||||
glRotatef( mRotateAngle, 1.0f, 1.0f, 1.0f ); // Rotate model around a vector
|
||||
mRotateAngle -= mRotateAngleRate; // update the rotation angle for next iteration
|
||||
glFinish(); // Ensure changes to GL state are complete
|
||||
|
||||
// Draw a colourful frame around the front face of the box
|
||||
// (provides a pleasing nesting effect when you connect the playout output to the capture input)
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
glColor3f( 1.0f, 0.0f, 0.0f );
|
||||
glVertex3f( 1.2f, 1.2f, 1.0f);
|
||||
glVertex3f( 1.0f, 1.0f, 1.0f);
|
||||
glColor3f( 0.0f, 0.0f, 1.0f );
|
||||
glVertex3f( 1.2f, -1.2f, 1.0f);
|
||||
glVertex3f( 1.0f, -1.0f, 1.0f);
|
||||
glColor3f( 0.0f, 1.0f, 0.0f );
|
||||
glVertex3f(-1.2f, -1.2f, 1.0f);
|
||||
glVertex3f(-1.0f, -1.0f, 1.0f);
|
||||
glColor3f( 1.0f, 1.0f, 0.0f );
|
||||
glVertex3f(-1.2f, 1.2f, 1.0f);
|
||||
glVertex3f(-1.0f, 1.0f, 1.0f);
|
||||
glColor3f( 1.0f, 0.0f, 0.0f );
|
||||
glVertex3f( 1.2f, 1.2f, 1.0f);
|
||||
glVertex3f( 1.0f, 1.0f, 1.0f);
|
||||
glEnd();
|
||||
|
||||
if (mHasNoInputSource)
|
||||
{
|
||||
// Draw a big X when no input is available on capture
|
||||
glBegin( GL_QUADS );
|
||||
glColor3f( 1.0f, 0.0f, 1.0f );
|
||||
glVertex3f( 0.8f, 0.9f, 1.0f );
|
||||
glVertex3f( 0.9f, 0.8f, 1.0f );
|
||||
glColor3f( 1.0f, 1.0f, 0.0f );
|
||||
glVertex3f( -0.8f, -0.9f, 1.0f );
|
||||
glVertex3f( -0.9f, -0.8f, 1.0f );
|
||||
glColor3f( 1.0f, 0.0f, 1.0f );
|
||||
glVertex3f( -0.8f, 0.9f, 1.0f );
|
||||
glVertex3f( -0.9f, 0.8f, 1.0f );
|
||||
glColor3f( 1.0f, 1.0f, 0.0f );
|
||||
glVertex3f( 0.8f, -0.9f, 1.0f );
|
||||
glVertex3f( 0.9f, -0.8f, 1.0f );
|
||||
glEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mFastTransferExtensionAvailable)
|
||||
{
|
||||
// Signal that we're about to draw using mCaptureTexture onto mFBOTexture
|
||||
VideoFrameTransfer::beginTextureInUse(VideoFrameTransfer::CPUtoGPU);
|
||||
}
|
||||
|
||||
// Pass texture unit 0 to the fragment shader as a uniform variable
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, mCaptureTexture);
|
||||
glUseProgram(mProgram);
|
||||
GLint locUYVYtex = glGetUniformLocation(mProgram, "UYVYtex");
|
||||
glUniform1i(locUYVYtex, 0); // Bind texture unit 0
|
||||
|
||||
// Draw front and back faces of box applying video texture to each face
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f ); // Top right of front side
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex3f( -1.0f, 1.0f, 1.0f ); // Top left of front side
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex3f( -1.0f, -1.0f, 1.0f ); // Bottom left of front side
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, -1.0f, 1.0f ); // Bottom right of front side
|
||||
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f ); // Top right of back side
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex3f( -1.0f, -1.0f, -1.0f ); // Top left of back side
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex3f( -1.0f, 1.0f, -1.0f ); // Bottom left of back side
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, -1.0f ); // Bottom right of back side
|
||||
glEnd();
|
||||
|
||||
// Draw left and right sides of box with partially transparent video texture
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.1f, 0.0f); glVertex3f( -1.0f, 1.0f, 1.0f ); // Top right of left side
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex3f( -1.0f, 1.0f, -1.0f ); // Top left of left side
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex3f( -1.0f, -1.0f, -1.0f ); // Bottom left of left side
|
||||
glTexCoord2f(0.1f, 1.0f); glVertex3f( -1.0f, -1.0f, 1.0f ); // Bottom right of left side
|
||||
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, -1.0f ); // Top right of right side
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f ); // Top left of right side
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, 1.0f ); // Bottom left of right side
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f ); // Bottom right of right side
|
||||
glEnd();
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glUseProgram(0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
renderEffect();
|
||||
|
||||
IDeckLinkVideoBuffer* outputVideoFrameBuffer;
|
||||
if (outputVideoFrame->QueryInterface(IID_IDeckLinkVideoBuffer, (void**)&outputVideoFrameBuffer) != S_OK)
|
||||
@@ -772,26 +847,93 @@ bool OpenGLComposite::Stop()
|
||||
return true;
|
||||
}
|
||||
|
||||
// Setup fragment shader to take YCbCr 4:2:2 video texture in UYVY macropixel format
|
||||
// and perform colour space conversion to RGBA in the GPU.
|
||||
bool OpenGLComposite::compileFragmentShader(int errorMessageSize, char* errorMessage)
|
||||
bool OpenGLComposite::ReloadShader()
|
||||
{
|
||||
GLsizei errorBufferSize;
|
||||
GLint compileResult, linkResult;
|
||||
std::string shaderPath = GetExecutableDirectory();
|
||||
std::string fragmentShaderSource;
|
||||
std::string loadError;
|
||||
char compilerErrorMessage[1024];
|
||||
|
||||
if (shaderPath.empty())
|
||||
EnterCriticalSection(&pMutex);
|
||||
wglMakeCurrent(hGLDC, hGLRC);
|
||||
|
||||
bool success = compileFragmentShader(sizeof(compilerErrorMessage), compilerErrorMessage);
|
||||
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
LeaveCriticalSection(&pMutex);
|
||||
|
||||
if (!success)
|
||||
MessageBoxA(NULL, compilerErrorMessage, "Slang shader reload failed", MB_OK);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void OpenGLComposite::destroyShaderProgram()
|
||||
{
|
||||
if (mProgram != 0)
|
||||
{
|
||||
CopyErrorMessage("Could not determine executable directory for fragment shader loading.", errorMessageSize, errorMessage);
|
||||
return false;
|
||||
glDeleteProgram(mProgram);
|
||||
mProgram = 0;
|
||||
}
|
||||
|
||||
shaderPath += "\\";
|
||||
shaderPath += kFragmentShaderFilename;
|
||||
if (mFragmentShader != 0)
|
||||
{
|
||||
glDeleteShader(mFragmentShader);
|
||||
mFragmentShader = 0;
|
||||
}
|
||||
|
||||
if (!LoadTextFile(shaderPath, fragmentShaderSource, loadError))
|
||||
if (mVertexShader != 0)
|
||||
{
|
||||
glDeleteShader(mVertexShader);
|
||||
mVertexShader = 0;
|
||||
}
|
||||
|
||||
mUYVYtexUniform = -1;
|
||||
}
|
||||
|
||||
void OpenGLComposite::renderEffect()
|
||||
{
|
||||
glViewport(0, 0, mFrameWidth, mFrameHeight);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
if (mHasNoInputSource)
|
||||
return;
|
||||
|
||||
if (mFastTransferExtensionAvailable)
|
||||
{
|
||||
// Signal that we're about to draw using mCaptureTexture onto mFBOTexture.
|
||||
VideoFrameTransfer::beginTextureInUse(VideoFrameTransfer::CPUtoGPU);
|
||||
}
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, mCaptureTexture);
|
||||
glUseProgram(mProgram);
|
||||
|
||||
if (mUYVYtexUniform >= 0)
|
||||
glUniform1i(mUYVYtexUniform, 0);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glUseProgram(0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
if (mFastTransferExtensionAvailable)
|
||||
VideoFrameTransfer::endTextureInUse(VideoFrameTransfer::CPUtoGPU);
|
||||
}
|
||||
|
||||
// Compile a fullscreen shader pass from the runtime Slang source. The Slang compiler
|
||||
// emits modern GLSL which we patch into a compatibility-profile shader that can run
|
||||
// inside the sample's WGL context.
|
||||
bool OpenGLComposite::compileFragmentShader(int errorMessageSize, char* errorMessage)
|
||||
{
|
||||
GLsizei errorBufferSize = 0;
|
||||
GLint compileResult = GL_FALSE;
|
||||
GLint linkResult = GL_FALSE;
|
||||
std::string fragmentShaderSource;
|
||||
std::string loadError;
|
||||
const char* vertexSource = kVertexShaderSource;
|
||||
|
||||
if (!BuildFragmentShaderSourceFromSlang(fragmentShaderSource, loadError))
|
||||
{
|
||||
CopyErrorMessage(loadError, errorMessageSize, errorMessage);
|
||||
return false;
|
||||
@@ -799,30 +941,50 @@ bool OpenGLComposite::compileFragmentShader(int errorMessageSize, char* errorMes
|
||||
|
||||
const char* fragmentSource = fragmentShaderSource.c_str();
|
||||
|
||||
mFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
glShaderSource(mFragmentShader, 1, (const GLchar**)&fragmentSource, NULL);
|
||||
glCompileShader(mFragmentShader);
|
||||
|
||||
glGetShaderiv(mFragmentShader, GL_COMPILE_STATUS, &compileResult);
|
||||
GLuint newVertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(newVertexShader, 1, (const GLchar**)&vertexSource, NULL);
|
||||
glCompileShader(newVertexShader);
|
||||
glGetShaderiv(newVertexShader, GL_COMPILE_STATUS, &compileResult);
|
||||
if (compileResult == GL_FALSE)
|
||||
{
|
||||
glGetShaderInfoLog(mFragmentShader, errorMessageSize, &errorBufferSize, errorMessage);
|
||||
glGetShaderInfoLog(newVertexShader, errorMessageSize, &errorBufferSize, errorMessage);
|
||||
glDeleteShader(newVertexShader);
|
||||
return false;
|
||||
}
|
||||
|
||||
mProgram = glCreateProgram();
|
||||
GLuint newFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(newFragmentShader, 1, (const GLchar**)&fragmentSource, NULL);
|
||||
glCompileShader(newFragmentShader);
|
||||
glGetShaderiv(newFragmentShader, GL_COMPILE_STATUS, &compileResult);
|
||||
if (compileResult == GL_FALSE)
|
||||
{
|
||||
glGetShaderInfoLog(newFragmentShader, errorMessageSize, &errorBufferSize, errorMessage);
|
||||
glDeleteShader(newVertexShader);
|
||||
glDeleteShader(newFragmentShader);
|
||||
return false;
|
||||
}
|
||||
|
||||
glAttachShader(mProgram, mFragmentShader);
|
||||
glLinkProgram(mProgram);
|
||||
|
||||
glGetProgramiv(mProgram, GL_LINK_STATUS, &linkResult);
|
||||
GLuint newProgram = glCreateProgram();
|
||||
glAttachShader(newProgram, newVertexShader);
|
||||
glAttachShader(newProgram, newFragmentShader);
|
||||
glLinkProgram(newProgram);
|
||||
glGetProgramiv(newProgram, GL_LINK_STATUS, &linkResult);
|
||||
if (linkResult == GL_FALSE)
|
||||
{
|
||||
glGetProgramInfoLog(mProgram, errorMessageSize, &errorBufferSize, errorMessage);
|
||||
glGetProgramInfoLog(newProgram, errorMessageSize, &errorBufferSize, errorMessage);
|
||||
glDeleteProgram(newProgram);
|
||||
glDeleteShader(newVertexShader);
|
||||
glDeleteShader(newFragmentShader);
|
||||
return false;
|
||||
}
|
||||
|
||||
destroyShaderProgram();
|
||||
|
||||
mProgram = newProgram;
|
||||
mVertexShader = newVertexShader;
|
||||
mFragmentShader = newFragmentShader;
|
||||
mUYVYtexUniform = glGetUniformLocation(mProgram, "UYVYtex");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ public:
|
||||
bool InitDeckLink();
|
||||
bool Start();
|
||||
bool Stop();
|
||||
bool ReloadShader();
|
||||
|
||||
void resizeGL(WORD width, WORD height);
|
||||
void paintGL();
|
||||
@@ -113,7 +114,9 @@ private:
|
||||
GLuint mIdColorBuf;
|
||||
GLuint mIdDepthBuf;
|
||||
GLuint mProgram;
|
||||
GLuint mVertexShader;
|
||||
GLuint mFragmentShader;
|
||||
GLint mUYVYtexUniform;
|
||||
GLfloat mRotateAngle;
|
||||
GLfloat mRotateAngleRate;
|
||||
int mViewWidth;
|
||||
@@ -121,6 +124,8 @@ private:
|
||||
|
||||
bool InitOpenGLState();
|
||||
bool compileFragmentShader(int errorMessageSize, char* errorMessage);
|
||||
void destroyShaderProgram();
|
||||
void renderEffect();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
#version 130
|
||||
|
||||
uniform sampler2D UYVYtex;
|
||||
|
||||
vec4 rec709YCbCr2rgba(float Y, float Cb, float Cr, float a)
|
||||
{
|
||||
float r, g, b;
|
||||
Y = (Y * 256.0 - 16.0) / 219.0;
|
||||
Cb = (Cb * 256.0 - 16.0) / 224.0 - 0.5;
|
||||
Cr = (Cr * 256.0 - 16.0) / 224.0 - 0.5;
|
||||
r = Y + 1.5748 * Cr;
|
||||
g = Y - 0.1873 * Cb - 0.4681 * Cr;
|
||||
b = Y + 1.8556 * Cb;
|
||||
return vec4(r, g, b, a);
|
||||
}
|
||||
|
||||
vec4 bilinear(vec4 W, vec4 X, vec4 Y, vec4 Z, vec2 weight)
|
||||
{
|
||||
vec4 m0 = mix(W, Z, weight.x);
|
||||
vec4 m1 = mix(X, Y, weight.x);
|
||||
return mix(m0, m1, weight.y);
|
||||
}
|
||||
|
||||
void textureGatherYUV(sampler2D UYVYsampler, vec2 tc, out vec4 W, out vec4 X, out vec4 Y, out vec4 Z)
|
||||
{
|
||||
ivec2 tx = ivec2(tc * textureSize(UYVYsampler, 0));
|
||||
ivec2 tmin = ivec2(0, 0);
|
||||
ivec2 tmax = textureSize(UYVYsampler, 0) - ivec2(1, 1);
|
||||
W = texelFetch(UYVYsampler, tx, 0);
|
||||
X = texelFetch(UYVYsampler, clamp(tx + ivec2(0, 1), tmin, tmax), 0);
|
||||
Y = texelFetch(UYVYsampler, clamp(tx + ivec2(1, 1), tmin, tmax), 0);
|
||||
Z = texelFetch(UYVYsampler, clamp(tx + ivec2(1, 0), tmin, tmax), 0);
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec2 tc = gl_TexCoord[0].st;
|
||||
float alpha = 0.7;
|
||||
|
||||
vec4 macro, macro_u, macro_r, macro_ur;
|
||||
vec4 pixel, pixel_r, pixel_u, pixel_ur;
|
||||
textureGatherYUV(UYVYtex, tc, macro, macro_u, macro_ur, macro_r);
|
||||
|
||||
vec2 off = fract(tc * textureSize(UYVYtex, 0));
|
||||
if (off.x > 0.5)
|
||||
{
|
||||
pixel = rec709YCbCr2rgba(macro.a, macro.b, macro.r, alpha);
|
||||
pixel_r = rec709YCbCr2rgba(macro_r.g, macro_r.b, macro_r.r, alpha);
|
||||
pixel_u = rec709YCbCr2rgba(macro_u.a, macro_u.b, macro_u.r, alpha);
|
||||
pixel_ur = rec709YCbCr2rgba(macro_ur.g, macro_ur.b, macro_ur.r, alpha);
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = rec709YCbCr2rgba(macro.g, macro.b, macro.r, alpha);
|
||||
pixel_r = rec709YCbCr2rgba(macro.a, macro.b, macro.r, alpha);
|
||||
pixel_u = rec709YCbCr2rgba(macro_u.g, macro_u.b, macro_u.r, alpha);
|
||||
pixel_ur = rec709YCbCr2rgba(macro_u.a, macro_u.b, macro_u.r, alpha);
|
||||
}
|
||||
|
||||
gl_FragColor = bilinear(pixel, pixel_u, pixel_ur, pixel_r, off);
|
||||
}
|
||||
79
apps/LoopThroughWithOpenGLCompositing/video_effect.slang
Normal file
79
apps/LoopThroughWithOpenGLCompositing/video_effect.slang
Normal file
@@ -0,0 +1,79 @@
|
||||
// Source-of-truth shader in Slang.
|
||||
// The current OpenGL sample still runs the checked-in GLSL fallback because it uses
|
||||
// legacy fixed-function texture coordinates in its fragment stage.
|
||||
|
||||
struct FragmentInput
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float2 texCoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
Texture2D<float4> UYVYtex;
|
||||
|
||||
float4 rec709YCbCr2rgba(float Y, float Cb, float Cr, float a)
|
||||
{
|
||||
Y = (Y * 256.0 - 16.0) / 219.0;
|
||||
Cb = (Cb * 256.0 - 16.0) / 224.0 - 0.5;
|
||||
Cr = (Cr * 256.0 - 16.0) / 224.0 - 0.5;
|
||||
|
||||
float r = Y + 1.5748 * Cr;
|
||||
float g = Y - 0.1873 * Cb - 0.4681 * Cr;
|
||||
float b = Y + 1.8556 * Cb;
|
||||
return float4(r, g, b, a);
|
||||
}
|
||||
|
||||
float4 bilinear(float4 W, float4 X, float4 Y, float4 Z, float2 weight)
|
||||
{
|
||||
float4 m0 = lerp(W, Z, weight.x);
|
||||
float4 m1 = lerp(X, Y, weight.x);
|
||||
return lerp(m0, m1, weight.y);
|
||||
}
|
||||
|
||||
void textureGatherYUV(Texture2D<float4> textureSampler, float2 tc, out float4 W, out float4 X, out float4 Y, out float4 Z)
|
||||
{
|
||||
uint width = 0;
|
||||
uint height = 0;
|
||||
textureSampler.GetDimensions(width, height);
|
||||
|
||||
int2 tx = int2(tc * float2(width, height));
|
||||
int2 tmin = int2(0, 0);
|
||||
int2 tmax = int2(int(width), int(height)) - int2(1, 1);
|
||||
|
||||
W = textureSampler.Load(int3(tx, 0));
|
||||
X = textureSampler.Load(int3(clamp(tx + int2(0, 1), tmin, tmax), 0));
|
||||
Y = textureSampler.Load(int3(clamp(tx + int2(1, 1), tmin, tmax), 0));
|
||||
Z = textureSampler.Load(int3(clamp(tx + int2(1, 0), tmin, tmax), 0));
|
||||
}
|
||||
|
||||
[shader("fragment")]
|
||||
float4 fragmentMain(FragmentInput input) : SV_Target
|
||||
{
|
||||
float2 tc = input.texCoord;
|
||||
float alpha = 0.7;
|
||||
|
||||
float4 macro, macroU, macroR, macroUR;
|
||||
float4 pixel, pixelR, pixelU, pixelUR;
|
||||
textureGatherYUV(UYVYtex, tc, macro, macroU, macroUR, macroR);
|
||||
|
||||
uint width = 0;
|
||||
uint height = 0;
|
||||
UYVYtex.GetDimensions(width, height);
|
||||
|
||||
float2 off = frac(tc * float2(width, height));
|
||||
if (off.x > 0.5)
|
||||
{
|
||||
pixel = rec709YCbCr2rgba(macro.a, macro.b, macro.r, alpha);
|
||||
pixelR = rec709YCbCr2rgba(macroR.g, macroR.b, macroR.r, alpha);
|
||||
pixelU = rec709YCbCr2rgba(macroU.a, macroU.b, macroU.r, alpha);
|
||||
pixelUR = rec709YCbCr2rgba(macroUR.g, macroUR.b, macroUR.r, alpha);
|
||||
}
|
||||
else
|
||||
{
|
||||
pixel = rec709YCbCr2rgba(macro.g, macro.b, macro.r, alpha);
|
||||
pixelR = rec709YCbCr2rgba(macro.a, macro.b, macro.r, alpha);
|
||||
pixelU = rec709YCbCr2rgba(macroU.g, macroU.b, macroU.r, alpha);
|
||||
pixelUR = rec709YCbCr2rgba(macroU.a, macroU.b, macroU.r, alpha);
|
||||
}
|
||||
|
||||
return bilinear(pixel, pixelU, pixelUR, pixelR, off);
|
||||
}
|
||||
Reference in New Issue
Block a user