Shader: Added code to load compiled shader
This commit is contained in:
@@ -145,6 +145,7 @@
|
|||||||
<ClInclude Include="include\Graphics\Graphics.h"/>
|
<ClInclude Include="include\Graphics\Graphics.h"/>
|
||||||
<ClInclude Include="include\Graphics\GraphicsConfig.h"/>
|
<ClInclude Include="include\Graphics\GraphicsConfig.h"/>
|
||||||
<ClInclude Include="include\Graphics\RenderPass.h"/>
|
<ClInclude Include="include\Graphics\RenderPass.h"/>
|
||||||
|
<ClInclude Include="include\Graphics\Shader.h" />
|
||||||
<ClInclude Include="include\Graphics\Texture.h"/>
|
<ClInclude Include="include\Graphics\Texture.h"/>
|
||||||
<ClInclude Include="include\Juliet.h"/>
|
<ClInclude Include="include\Juliet.h"/>
|
||||||
<ClInclude Include="include\pch.h"/>
|
<ClInclude Include="include\pch.h"/>
|
||||||
|
|||||||
@@ -6,4 +6,6 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
// Returns the path to the application directory
|
// Returns the path to the application directory
|
||||||
extern JULIET_API String GetBasePath();
|
extern JULIET_API String GetBasePath();
|
||||||
|
|
||||||
|
extern JULIET_API bool IsAbsolutePath(String path);
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -14,10 +14,12 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
++left;
|
++left;
|
||||||
++right;
|
++right;
|
||||||
|
--size;
|
||||||
}
|
}
|
||||||
return size ? *left - *right : 0;
|
return size ? *left - *right : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: homemade versions
|
||||||
#define MemSet memset
|
#define MemSet memset
|
||||||
#define MemCopy memcpy
|
#define MemCopy memcpy
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Core/Common/NonNullPtr.h>
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
#include <Core/Common/String.h>
|
||||||
#include <Core/HAL/Display/Display.h>
|
#include <Core/HAL/Display/Display.h>
|
||||||
#include <Core/Math/Shape.h>
|
#include <Core/Math/Shape.h>
|
||||||
#include <Graphics/GraphicsConfig.h>
|
#include <Graphics/GraphicsConfig.h>
|
||||||
#include <Graphics/RenderPass.h>
|
#include <Graphics/RenderPass.h>
|
||||||
|
#include <Graphics/Shader.h>
|
||||||
#include <Juliet.h>
|
#include <Juliet.h>
|
||||||
|
|
||||||
// Graphics Interface
|
// Graphics Interface
|
||||||
@@ -104,4 +106,8 @@ namespace Juliet
|
|||||||
extern JULIET_API void SetScissorRect(NonNullPtr<RenderPass> renderPass, const Rectangle& rectangle);
|
extern JULIET_API void SetScissorRect(NonNullPtr<RenderPass> renderPass, const Rectangle& rectangle);
|
||||||
extern JULIET_API void SetBlendConstants(NonNullPtr<RenderPass> renderPass, FColor blendConstants);
|
extern JULIET_API void SetBlendConstants(NonNullPtr<RenderPass> renderPass, FColor blendConstants);
|
||||||
extern JULIET_API void SetStencilReference(NonNullPtr<RenderPass> renderPass, uint8 reference);
|
extern JULIET_API void SetStencilReference(NonNullPtr<RenderPass> renderPass, uint8 reference);
|
||||||
|
|
||||||
|
// Shaders
|
||||||
|
extern JULIET_API Shader* CreateShader(NonNullPtr<GraphicsDevice> device, String filename, ShaderCreateInfo& shaderCreateInfo);
|
||||||
|
extern JULIET_API void DestroyShader(NonNullPtr<GraphicsDevice> driver, NonNullPtr<Shader> shader);
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
23
Juliet/include/Graphics/Shader.h
Normal file
23
Juliet/include/Graphics/Shader.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/Common/String.h>
|
||||||
|
|
||||||
|
namespace Juliet
|
||||||
|
{
|
||||||
|
// Opaque type
|
||||||
|
struct Shader;
|
||||||
|
|
||||||
|
enum class ShaderStage : uint8
|
||||||
|
{
|
||||||
|
Vertex,
|
||||||
|
Fragment,
|
||||||
|
Compute
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ShaderCreateInfo
|
||||||
|
{
|
||||||
|
ShaderStage Stage;
|
||||||
|
String EntryPoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Juliet
|
||||||
@@ -22,6 +22,15 @@ namespace Juliet
|
|||||||
return CachedBasePath;
|
return CachedBasePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsAbsolutePath(String path)
|
||||||
|
{
|
||||||
|
if (!IsValid(path))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Platform::IsAbsolutePath(path);
|
||||||
|
}
|
||||||
|
|
||||||
void InitFilesystem() {}
|
void InitFilesystem() {}
|
||||||
|
|
||||||
void ShutdownFilesystem()
|
void ShutdownFilesystem()
|
||||||
|
|||||||
@@ -3,4 +3,5 @@
|
|||||||
namespace Juliet::Platform
|
namespace Juliet::Platform
|
||||||
{
|
{
|
||||||
extern String GetBasePath();
|
extern String GetBasePath();
|
||||||
}
|
extern bool IsAbsolutePath(String path);
|
||||||
|
} // namespace Juliet::Platform
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ namespace Juliet::Platform
|
|||||||
{
|
{
|
||||||
// Allocate a buffer that could fit the module size.
|
// Allocate a buffer that could fit the module size.
|
||||||
// Max Path is a good start but could be bigger if the path include long path prefix
|
// Max Path is a good start but could be bigger if the path include long path prefix
|
||||||
size_t bufferSize=MAX_PATH;
|
size_t bufferSize = MAX_PATH;
|
||||||
auto buffer = static_cast<char*>(Calloc(MAX_PATH, sizeof(char)));
|
auto buffer = static_cast<char*>(Calloc(MAX_PATH, sizeof(char)));
|
||||||
if (buffer == nullptr)
|
if (buffer == nullptr)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
@@ -41,7 +41,6 @@ namespace Juliet::Platform
|
|||||||
Log(LogLevel::Error, LogCategory::Core, "Filesystem: Cannot locate executable path");
|
Log(LogLevel::Error, LogCategory::Core, "Filesystem: Cannot locate executable path");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
for (idx = moduleFilenameLength - 1; idx > 0; --idx)
|
for (idx = moduleFilenameLength - 1; idx > 0; --idx)
|
||||||
{
|
{
|
||||||
@@ -56,4 +55,40 @@ namespace Juliet::Platform
|
|||||||
|
|
||||||
return WrapString(buffer);
|
return WrapString(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsAbsolutePath(String path)
|
||||||
|
{
|
||||||
|
if (path.Data || path.Size == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From https://learn.microsoft.com/en-ca/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#fully_qualified_vs._relative_paths
|
||||||
|
// Windows path starts with either:
|
||||||
|
// A UNC name of any format, which always start with two backslash characters ("\\"). For more information, see the next section.
|
||||||
|
// A disk designator with a backslash, for example "C:\" or "d:\".
|
||||||
|
// A single backslash, for example, "\directory" or "\file.txt". This is also referred to as an absolute path.
|
||||||
|
// We will only handle the first two. Single backslash is weird.
|
||||||
|
const char* pathStr = path.Data;
|
||||||
|
size_t pathLen = path.Size;
|
||||||
|
|
||||||
|
if (pathLen > 1)
|
||||||
|
{
|
||||||
|
if (pathStr[0] == '\\' && pathStr[1] == '\\')
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathLen > 2)
|
||||||
|
{
|
||||||
|
char first = pathStr[0];
|
||||||
|
char second = pathStr[1];
|
||||||
|
char third = pathStr[2];
|
||||||
|
return ((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z')) && second == ':' &&
|
||||||
|
(third == '\\' || third == '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} // namespace Juliet::Platform
|
} // namespace Juliet::Platform
|
||||||
|
|||||||
@@ -248,16 +248,16 @@ namespace Juliet::Internal
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
IOStreamInterface interface = {};
|
IOStreamInterface iface = {};
|
||||||
interface.Version = sizeof(interface);
|
iface.Version = sizeof(iface);
|
||||||
if (GetFileType(hFile) == FILE_TYPE_DISK)
|
if (GetFileType(hFile) == FILE_TYPE_DISK)
|
||||||
{
|
{
|
||||||
interface.Size = FileSize;
|
iface.Size = FileSize;
|
||||||
interface.Seek = FileSeek;
|
iface.Seek = FileSeek;
|
||||||
}
|
}
|
||||||
interface.Read = FileRead;
|
iface.Read = FileRead;
|
||||||
interface.Write = FileWrite;
|
iface.Write = FileWrite;
|
||||||
interface.Close = FileClose;
|
iface.Close = FileClose;
|
||||||
|
|
||||||
payload->Handle = hFile;
|
payload->Handle = hFile;
|
||||||
payload->IsAppending = isAppending;
|
payload->IsAppending = isAppending;
|
||||||
@@ -266,14 +266,14 @@ namespace Juliet::Internal
|
|||||||
payload->Data = static_cast<char*>(Malloc(kFileReadBufferSize));
|
payload->Data = static_cast<char*>(Malloc(kFileReadBufferSize));
|
||||||
if (!payload->Data)
|
if (!payload->Data)
|
||||||
{
|
{
|
||||||
interface.Close(payload);
|
iface.Close(payload);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
IOStream* stream = IOFromInterface(&interface, payload);
|
IOStream* stream = IOFromInterface(&iface, payload);
|
||||||
if (!stream)
|
if (!stream)
|
||||||
{
|
{
|
||||||
interface.Close(payload);
|
iface.Close(payload);
|
||||||
}
|
}
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,54 @@
|
|||||||
#include <pch.h>
|
#include <pch.h>
|
||||||
|
|
||||||
|
#include <Core/Memory/Allocator.h>
|
||||||
#include <Graphics/D3D12/D3D12Shader.h>
|
#include <Graphics/D3D12/D3D12Shader.h>
|
||||||
|
|
||||||
namespace Juliet::D3D12
|
namespace Juliet::D3D12
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
void CompileShader(const char* shaderFile) {}
|
struct D3D12Shader
|
||||||
|
{
|
||||||
|
ByteBuffer ByteCode;
|
||||||
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void LoadShader(const char* shaderFile)
|
Shader* CreateShader(NonNullPtr<GPUDriver> driver, ByteBuffer shaderByteCode, ShaderCreateInfo& shaderCreateInfo)
|
||||||
{
|
{
|
||||||
CompileShader(shaderFile);
|
if (!IsValid(shaderByteCode))
|
||||||
|
{
|
||||||
|
LogError(LogCategory::Graphics, "Invalid shader byte code");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t allocSize = sizeof(D3D12Shader) + shaderByteCode.Size;
|
||||||
|
auto shader = static_cast<D3D12Shader*>(Malloc(allocSize));
|
||||||
|
if (!shader)
|
||||||
|
{
|
||||||
|
LogError(LogCategory::Graphics, "Cannot allocate a new D3D12Shader: Out of memory");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uses the bytes after the struct to store the shader byte code.
|
||||||
|
// TODO:MemoryArena Will use memory arena later that will do the same thing
|
||||||
|
shader->ByteCode.Data = reinterpret_cast<Byte*>(shader + 1);
|
||||||
|
shader->ByteCode.Size = shaderByteCode.Size;
|
||||||
|
MemCopy(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size);
|
||||||
|
|
||||||
|
// Make sure the data is correctly copied
|
||||||
|
if (MemCompare(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size) != 0)
|
||||||
|
{
|
||||||
|
LogError(LogCategory::Graphics, "Memory copy failed");
|
||||||
|
Free(shader);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reinterpret_cast<Shader*>(shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyShader(NonNullPtr<GPUDriver> driver, NonNullPtr<Shader> shader)
|
||||||
|
{
|
||||||
|
auto d3d12shader = reinterpret_cast<D3D12Shader*>(shader.Get());
|
||||||
|
Free(d3d12shader);
|
||||||
}
|
}
|
||||||
} // namespace Juliet::D3D12
|
} // namespace Juliet::D3D12
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/Common/NonNullPtr.h>
|
||||||
|
#include <Graphics/GraphicsDevice.h>
|
||||||
|
#include <Graphics/Shader.h>
|
||||||
|
|
||||||
namespace Juliet::D3D12
|
namespace Juliet::D3D12
|
||||||
{
|
{
|
||||||
extern void LoadShader(const char* shaderFile);
|
extern Shader* CreateShader(NonNullPtr<GPUDriver> driver, ByteBuffer shaderByteCode, ShaderCreateInfo& shaderCreateInfo);
|
||||||
}
|
extern void DestroyShader(NonNullPtr<GPUDriver> driver, NonNullPtr<Shader> shader);
|
||||||
|
} // namespace Juliet::D3D12
|
||||||
|
|||||||
@@ -618,6 +618,9 @@ namespace Juliet::D3D12
|
|||||||
device->QueryFence = QueryFence;
|
device->QueryFence = QueryFence;
|
||||||
device->ReleaseFence = ReleaseFence;
|
device->ReleaseFence = ReleaseFence;
|
||||||
|
|
||||||
|
device->CreateShader = CreateShader;
|
||||||
|
device->DestroyShader = DestroyShader;
|
||||||
|
|
||||||
device->Driver = driver;
|
device->Driver = driver;
|
||||||
driver->GraphicsDevice = device;
|
driver->GraphicsDevice = device;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <DX12CommandList.h>
|
|
||||||
#include <pch.h>
|
#include <pch.h>
|
||||||
|
|
||||||
|
#include <Core/HAL/Filesystem/Filesystem.h>
|
||||||
|
#include <Core/HAL/IO/IOStream.h>
|
||||||
#include <Graphics/Graphics.h>
|
#include <Graphics/Graphics.h>
|
||||||
#include <Graphics/GraphicsDevice.h>
|
#include <Graphics/GraphicsDevice.h>
|
||||||
|
|
||||||
@@ -175,4 +176,41 @@ namespace Juliet
|
|||||||
commandListHeader->Device->SetStencilReference(commandList, reference);
|
commandListHeader->Device->SetStencilReference(commandList, reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shaders
|
||||||
|
Shader* CreateShader(NonNullPtr<GraphicsDevice> device, String filename, ShaderCreateInfo& shaderCreateInfo)
|
||||||
|
{
|
||||||
|
ByteBuffer shaderByteCode = {};
|
||||||
|
|
||||||
|
// Create path from filename
|
||||||
|
if (IsAbsolutePath(filename))
|
||||||
|
{
|
||||||
|
shaderByteCode = LoadFile(filename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Add path builder in the lib
|
||||||
|
String base = GetBasePath();
|
||||||
|
char inplaceBuffer[256];
|
||||||
|
snprintf(inplaceBuffer, sizeof(inplaceBuffer), "%s%s", base.Data, filename.Data);
|
||||||
|
String absolutePath = WrapString(inplaceBuffer);
|
||||||
|
shaderByteCode = LoadFile(absolutePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsValid(shaderByteCode))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader* shader = device->CreateShader(device->Driver, shaderByteCode, shaderCreateInfo);
|
||||||
|
|
||||||
|
Free(shaderByteCode);
|
||||||
|
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyShader(NonNullPtr<GraphicsDevice> device, NonNullPtr<Shader> shader)
|
||||||
|
{
|
||||||
|
device->DestroyShader(device->Driver, shader);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ namespace Juliet
|
|||||||
bool (*QueryFence)(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
|
bool (*QueryFence)(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
|
||||||
void (*ReleaseFence)(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
|
void (*ReleaseFence)(NonNullPtr<GPUDriver> driver, NonNullPtr<Fence> fence);
|
||||||
|
|
||||||
|
// Shaders
|
||||||
|
Shader* (*CreateShader)(NonNullPtr<GPUDriver> driver, ByteBuffer shaderByteCode, ShaderCreateInfo& shaderCreateInfo);
|
||||||
|
void (*DestroyShader)(NonNullPtr<GPUDriver> driver, NonNullPtr<Shader> shader);
|
||||||
|
|
||||||
const char* Name = "Unknown";
|
const char* Name = "Unknown";
|
||||||
GPUDriver* Driver = nullptr;
|
GPUDriver* Driver = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include <Graphics/Graphics.h>
|
#include <Graphics/Graphics.h>
|
||||||
#include <Graphics/GraphicsConfig.h>
|
#include <Graphics/GraphicsConfig.h>
|
||||||
#include <Graphics/RenderPass.h>
|
#include <Graphics/RenderPass.h>
|
||||||
#include <Windows.h>
|
|
||||||
|
|
||||||
#include <Core/Common/String.h>
|
#include <Core/Common/String.h>
|
||||||
#include <Core/Memory/Utils.h>
|
#include <Core/Memory/Utils.h>
|
||||||
@@ -59,6 +58,20 @@ void JulietApplication::Init()
|
|||||||
{
|
{
|
||||||
AttachToWindow(GraphicsDevice, MainWindow);
|
AttachToWindow(GraphicsDevice, MainWindow);
|
||||||
|
|
||||||
|
{
|
||||||
|
// Create graphics pipeline
|
||||||
|
// TODO: Assets management that handles path to assets or something.
|
||||||
|
String shaderPath = WrapString("../../../Assets/compiled/Triangle.vert.dxil");
|
||||||
|
ShaderCreateInfo shaderCI = {};
|
||||||
|
shaderCI.Stage = ShaderStage::Vertex;
|
||||||
|
shaderCI.EntryPoint = WrapString("main");
|
||||||
|
Shader* shader = CreateShader(GraphicsDevice, shaderPath, shaderCI);
|
||||||
|
if (shader)
|
||||||
|
{
|
||||||
|
DestroyShader(GraphicsDevice, shader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GameCode.Functions = reinterpret_cast<void**>(&Game);
|
GameCode.Functions = reinterpret_cast<void**>(&Game);
|
||||||
GameCode.FunctionCount = ArraySize(GameFunctionTable);
|
GameCode.FunctionCount = ArraySize(GameFunctionTable);
|
||||||
GameCode.FunctionNames = GameFunctionTable;
|
GameCode.FunctionNames = GameFunctionTable;
|
||||||
@@ -167,12 +180,14 @@ JulietApplication& GetEditorApplication()
|
|||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
CreateMutex(0, false, L"Local\\Juliet.App");
|
// Allow only one instance to be launched.
|
||||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
// Need to create Mutex code in the lib because i dont want to include windows.h in this file anymore
|
||||||
{
|
// CreateMutex(0, false, L"Local\\Juliet.App");
|
||||||
MessageBox(nullptr, L"An instance of Juliet is already running.", L"Juliet", MB_OK | MB_ICONEXCLAMATION);
|
// if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||||
return EXIT_FAILURE;
|
// {
|
||||||
}
|
// MessageBox(nullptr, L"An instance of Juliet is already running.", L"Juliet", MB_OK | MB_ICONEXCLAMATION);
|
||||||
|
// return EXIT_FAILURE;
|
||||||
|
// }
|
||||||
|
|
||||||
StartApplication(EditorApplication, JulietInit_Flags::Display);
|
StartApplication(EditorApplication, JulietInit_Flags::Display);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user