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\GraphicsConfig.h"/>
|
||||
<ClInclude Include="include\Graphics\RenderPass.h"/>
|
||||
<ClInclude Include="include\Graphics\Shader.h" />
|
||||
<ClInclude Include="include\Graphics\Texture.h"/>
|
||||
<ClInclude Include="include\Juliet.h"/>
|
||||
<ClInclude Include="include\pch.h"/>
|
||||
|
||||
@@ -6,4 +6,6 @@ namespace Juliet
|
||||
{
|
||||
// Returns the path to the application directory
|
||||
extern JULIET_API String GetBasePath();
|
||||
|
||||
extern JULIET_API bool IsAbsolutePath(String path);
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -14,10 +14,12 @@ namespace Juliet
|
||||
{
|
||||
++left;
|
||||
++right;
|
||||
--size;
|
||||
}
|
||||
return size ? *left - *right : 0;
|
||||
}
|
||||
|
||||
// TODO: homemade versions
|
||||
#define MemSet memset
|
||||
#define MemCopy memcpy
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Core/Common/String.h>
|
||||
#include <Core/HAL/Display/Display.h>
|
||||
#include <Core/Math/Shape.h>
|
||||
#include <Graphics/GraphicsConfig.h>
|
||||
#include <Graphics/RenderPass.h>
|
||||
#include <Graphics/Shader.h>
|
||||
#include <Juliet.h>
|
||||
|
||||
// Graphics Interface
|
||||
@@ -104,4 +106,8 @@ namespace Juliet
|
||||
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 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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool IsAbsolutePath(String path)
|
||||
{
|
||||
if (!IsValid(path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Platform::IsAbsolutePath(path);
|
||||
}
|
||||
|
||||
void InitFilesystem() {}
|
||||
|
||||
void ShutdownFilesystem()
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
namespace Juliet::Platform
|
||||
{
|
||||
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.
|
||||
// Max Path is a good start but could be bigger if the path include long path prefix
|
||||
size_t bufferSize=MAX_PATH;
|
||||
auto buffer = static_cast<char*>(Calloc(MAX_PATH, sizeof(char)));
|
||||
size_t bufferSize = MAX_PATH;
|
||||
auto buffer = static_cast<char*>(Calloc(MAX_PATH, sizeof(char)));
|
||||
if (buffer == nullptr)
|
||||
{
|
||||
return {};
|
||||
@@ -41,7 +41,6 @@ namespace Juliet::Platform
|
||||
Log(LogLevel::Error, LogCategory::Core, "Filesystem: Cannot locate executable path");
|
||||
}
|
||||
|
||||
|
||||
size_t idx = 0;
|
||||
for (idx = moduleFilenameLength - 1; idx > 0; --idx)
|
||||
{
|
||||
@@ -56,4 +55,40 @@ namespace Juliet::Platform
|
||||
|
||||
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
|
||||
|
||||
@@ -248,16 +248,16 @@ namespace Juliet::Internal
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IOStreamInterface interface = {};
|
||||
interface.Version = sizeof(interface);
|
||||
IOStreamInterface iface = {};
|
||||
iface.Version = sizeof(iface);
|
||||
if (GetFileType(hFile) == FILE_TYPE_DISK)
|
||||
{
|
||||
interface.Size = FileSize;
|
||||
interface.Seek = FileSeek;
|
||||
iface.Size = FileSize;
|
||||
iface.Seek = FileSeek;
|
||||
}
|
||||
interface.Read = FileRead;
|
||||
interface.Write = FileWrite;
|
||||
interface.Close = FileClose;
|
||||
iface.Read = FileRead;
|
||||
iface.Write = FileWrite;
|
||||
iface.Close = FileClose;
|
||||
|
||||
payload->Handle = hFile;
|
||||
payload->IsAppending = isAppending;
|
||||
@@ -266,14 +266,14 @@ namespace Juliet::Internal
|
||||
payload->Data = static_cast<char*>(Malloc(kFileReadBufferSize));
|
||||
if (!payload->Data)
|
||||
{
|
||||
interface.Close(payload);
|
||||
iface.Close(payload);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IOStream* stream = IOFromInterface(&interface, payload);
|
||||
IOStream* stream = IOFromInterface(&iface, payload);
|
||||
if (!stream)
|
||||
{
|
||||
interface.Close(payload);
|
||||
iface.Close(payload);
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,54 @@
|
||||
#include <pch.h>
|
||||
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Graphics/D3D12/D3D12Shader.h>
|
||||
|
||||
namespace Juliet::D3D12
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void CompileShader(const char* shaderFile) {}
|
||||
struct D3D12Shader
|
||||
{
|
||||
ByteBuffer ByteCode;
|
||||
};
|
||||
} // 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
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Graphics/GraphicsDevice.h>
|
||||
#include <Graphics/Shader.h>
|
||||
|
||||
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->ReleaseFence = ReleaseFence;
|
||||
|
||||
device->CreateShader = CreateShader;
|
||||
device->DestroyShader = DestroyShader;
|
||||
|
||||
device->Driver = driver;
|
||||
driver->GraphicsDevice = device;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <DX12CommandList.h>
|
||||
#include <pch.h>
|
||||
|
||||
#include <Core/HAL/Filesystem/Filesystem.h>
|
||||
#include <Core/HAL/IO/IOStream.h>
|
||||
#include <Graphics/Graphics.h>
|
||||
#include <Graphics/GraphicsDevice.h>
|
||||
|
||||
@@ -175,4 +176,41 @@ namespace Juliet
|
||||
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
|
||||
|
||||
@@ -64,6 +64,10 @@ namespace Juliet
|
||||
bool (*QueryFence)(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";
|
||||
GPUDriver* Driver = nullptr;
|
||||
};
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <Graphics/Graphics.h>
|
||||
#include <Graphics/GraphicsConfig.h>
|
||||
#include <Graphics/RenderPass.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#include <Core/Common/String.h>
|
||||
#include <Core/Memory/Utils.h>
|
||||
@@ -59,6 +58,20 @@ void JulietApplication::Init()
|
||||
{
|
||||
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.FunctionCount = ArraySize(GameFunctionTable);
|
||||
GameCode.FunctionNames = GameFunctionTable;
|
||||
@@ -167,12 +180,14 @@ JulietApplication& GetEditorApplication()
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
CreateMutex(0, false, L"Local\\Juliet.App");
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
MessageBox(nullptr, L"An instance of Juliet is already running.", L"Juliet", MB_OK | MB_ICONEXCLAMATION);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// Allow only one instance to be launched.
|
||||
// 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");
|
||||
// if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
// {
|
||||
// MessageBox(nullptr, L"An instance of Juliet is already running.", L"Juliet", MB_OK | MB_ICONEXCLAMATION);
|
||||
// return EXIT_FAILURE;
|
||||
// }
|
||||
|
||||
StartApplication(EditorApplication, JulietInit_Flags::Display);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user