Some slang progress

This commit is contained in:
2024-12-17 12:32:44 -06:00
parent b3c2e0114f
commit b5958189cf
33 changed files with 617 additions and 255 deletions

View File

@@ -10,6 +10,7 @@ target_link_libraries(${DAWN_TARGET_NAME}
glm::glm
nlohmann_json::nlohmann_json
freetype
slang
)
# Includes
@@ -37,5 +38,6 @@ add_subdirectory(ui)
# Assets
tool_copy(en en.json)
tool_copy(helloShader shaders/hello-world.slang)
add_dependencies(${DAWN_TARGET_NAME} dawnassets)

View File

@@ -5,6 +5,7 @@
#include "AssetLoader.hpp"
#include "assert/assert.hpp"
#include "asset/AssetManager.hpp"
using namespace Dawn;
@@ -27,6 +28,12 @@ std::shared_ptr<AssetManager> AssetLoader::getAssetManager() {
return am;
}
void AssetLoader::loadImmediately() {
while(!this->loaded) {
this->getAssetManager()->update();
}
}
AssetLoader::~AssetLoader() {
this->loaded = false;
}

View File

@@ -57,6 +57,11 @@ namespace Dawn {
* @return The asset manager.
*/
std::shared_ptr<AssetManager> getAssetManager();
/**
* Load the asset immediately, this is blocking on the main thread.
*/
void loadImmediately();
/**
* Dispose the asset item.

View File

@@ -9,6 +9,8 @@ target_sources(${DAWN_TARGET_NAME}
TextureLoader.cpp
JSONLoader.cpp
TrueTypeLoader.cpp
ShaderLoader.cpp
StringLoader.cpp
)
# Subdirs

View File

@@ -0,0 +1,137 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "ShaderLoader.hpp"
#include "assert/assert.hpp"
#include "asset/AssetManager.hpp"
#include "game/Game.hpp"
#include <fstream>
using namespace Dawn;
const std::string ShaderLoader::ASSET_TYPE = "shader";
ShaderLoader::ShaderLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
) :
AssetLoader(assetManager, name),
state(ShaderLoaderState::INITIAL)
{
}
void ShaderLoader::updateAsync() {
}
void ShaderLoader::updateSync() {
if(state != ShaderLoaderState::INITIAL) return;
this->state = ShaderLoaderState::LOADING;
assertFalse(loaded, "ShaderLoader already loaded.");
auto sm = this->getAssetManager()->getGame()->shaderManager;
// Load the shader string
Slang::ComPtr<IBlob> diagnostics;
module = sm->session->loadModule(
this->name.c_str(),
diagnostics.writeRef()
);
// Get list of entry points and create components
int32_t definedEntryPointCount = module->getDefinedEntryPointCount();
IComponentType** components = new IComponentType*[definedEntryPointCount + 1];
int32_t j = 0;
components[j++] = module;
for(auto i = 0; i < definedEntryPointCount; i++) {
Slang::ComPtr<IEntryPoint> ep;
auto result = module->getDefinedEntryPoint(i, ep.writeRef());
if(result != SLANG_OK) {
assertUnreachable("Failed to get entry point.");
return;
}
auto name = ep->getFunctionReflection()->getName();
std::cout << "Found entry point: " << name << std::endl;
entryPoints.push_back(std::string(name));
components[j++] = ep;
}
// Create the composite component type
sm->session->createCompositeComponentType(
components,
sizeof(components) / sizeof(components[0]),
program.writeRef()
);
// Link the program.
auto result = program->link(linkedProgram.writeRef(), diagnostics.writeRef());
if(diagnostics) {
assertUnreachable("%s\n", (const char*) diagnostics->getBufferPointer());
return;
}
// result
Slang::ComPtr<IBlob> blob;
auto result2 = linkedProgram->getEntryPointCode(
0,
0,
blob.writeRef(),
diagnostics.writeRef()
);
if(diagnostics) {
assertUnreachable("%s\n", (const char*) diagnostics->getBufferPointer());
}
this->state = ShaderLoaderState::LOADED;
this->loaded = true;
}
std::string ShaderLoader::getAssetType() const {
return ShaderLoader::ASSET_TYPE;
}
std::string ShaderLoader::getEntryPointCode(const std::string &entryPoint) {
assertTrue(loaded, "ShaderLoader not loaded.");
assertNotNull(linkedProgram, "ShaderLoader linkedProgram is null.");
// Get the entry point index
int32_t entryIndex = -1;
for(auto i = 0; i < entryPoints.size(); i++) {
if(entryPoints[i] != entryPoint) continue;
entryIndex = i;
break;
}
assertTrue(entryIndex != -1, "EntryPoint not found.");
// Find the entry point code
Slang::ComPtr<IBlob> blob;
Slang::ComPtr<IBlob> diagnostics;
auto result = linkedProgram->getEntryPointCode(
entryIndex,
0,
blob.writeRef(),
diagnostics.writeRef()
);
if(diagnostics) {
assertUnreachable("%s\n", (const char*) diagnostics->getBufferPointer());
return "";
}
return std::string((const char*)blob->getBufferPointer());
}
ShaderLoader::~ShaderLoader() {
if(linkedProgram) {
linkedProgram->release();
linkedProgram = nullptr;
}
}

View File

@@ -0,0 +1,40 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "asset/AssetLoader.hpp"
#include "asset/AssetDataLoader.hpp"
#include "display/shader/ShaderManager.hpp"
namespace Dawn {
enum class ShaderLoaderState {
INITIAL,
LOADING,
LOADED
};
class ShaderLoader : public AssetLoader {
protected:
enum ShaderLoaderState state;
public:
const static std::string ASSET_TYPE;
std::vector<std::string> entryPoints;
Slang::ComPtr<IComponentType> linkedProgram;
Slang::ComPtr<IComponentType> program;
IModule* module;
ShaderLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
);
void updateSync() override;
void updateAsync() override;
std::string getAssetType() const override;
std::string getEntryPointCode(const std::string &entryPoint);
~ShaderLoader();
};
}

View File

@@ -0,0 +1,38 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "StringLoader.hpp"
using namespace Dawn;
const std::string StringLoader::ASSET_TYPE = "string";
StringLoader::StringLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
) :
AssetLoader(assetManager, name),
loader(name),
state(StringLoaderState::INITIAL)
{
}
void StringLoader::updateSync() {
}
void StringLoader::updateAsync() {
if(this->state != StringLoaderState::INITIAL) return;
this->state = StringLoaderState::LOADING_STRING;
this->data = this->loader.getEntireContentsAsString();
this->state = StringLoaderState::DONE;
this->loaded = true;
}
std::string StringLoader::getAssetType() const {
return StringLoader::ASSET_TYPE;
}
StringLoader::~StringLoader() {
}

View File

@@ -0,0 +1,36 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "asset/AssetLoader.hpp"
#include "asset/AssetDataLoader.hpp"
namespace Dawn {
enum class StringLoaderState {
INITIAL,
LOADING_STRING,
DONE
};
class StringLoader : public AssetLoader {
protected:
AssetDataLoader loader;
enum StringLoaderState state;
public:
const static std::string ASSET_TYPE;
std::string data;
StringLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
);
void updateSync() override;
void updateAsync() override;
std::string getAssetType() const override;
~StringLoader();
};
}

View File

@@ -4,13 +4,16 @@
// https://opensource.org/licenses/MIT
#include "Material.hpp"
#include "game/Game.hpp"
using namespace Dawn;
void Material::onInit() {
this->lockedShaders = this->getLockedShaders(
getGame()->renderHost->shaderManager
);
}
void Material::onDispose() {
this->lockedShaders.clear();
}

View File

@@ -12,7 +12,19 @@ namespace Dawn {
public SceneComponent,
public IRenderableComponent
{
private:
std::vector<std::shared_ptr<IShaderBase>> lockedShaders;
protected:
/**
* Locks the shaders to be used for rendering.
*
* @param shaderManager Shader manager to use.
* @return List of shaders to be used.
*/
virtual std::vector<std::shared_ptr<IShaderBase>> getLockedShaders(
ShaderManager &shaderManager
) = 0;
public:
void onInit() override;

View File

@@ -9,6 +9,14 @@
using namespace Dawn;
std::vector<
std::shared_ptr<IShaderBase>
> SimpleTexturedMaterial::getLockedShaders(ShaderManager &shaderManager) {
return {
shaderManager.getShader<SimpleTexturedShader>()
};
}
void SimpleTexturedMaterial::load(std::shared_ptr<SceneLoadContext> ctx) {
if(ctx->data.contains("color")) {
this->setColor(JSON::color(ctx->data["color"]));

View File

@@ -14,6 +14,11 @@ namespace Dawn {
struct SimpleTexturedShaderData data;
std::shared_ptr<Texture> texture;
protected:
std::vector<std::shared_ptr<IShaderBase>> getLockedShaders(
ShaderManager &shaderManager
) override;
public:
void load(std::shared_ptr<SceneLoadContext> ctx) override;

View File

@@ -8,4 +8,6 @@ target_sources(${DAWN_TARGET_NAME}
PRIVATE
IShader.cpp
IShaderStage.cpp
ShaderManager.cpp
ShaderManagerSlangFileSystem.cpp
)

View File

@@ -0,0 +1,48 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "ShaderManager.hpp"
#include "assert/assert.hpp"
using namespace Dawn;
ShaderManager::ShaderManager() {
}
void ShaderManager::init(const std::shared_ptr<Game> &game) {
assertNotNull(game, "Game instance must not be null.");
this->game = game;
// Create the file system
this->fileSystem.sm = shared_from_this();
// Create the global session
createGlobalSession(globalSession.writeRef());
// Set the target description, TODO: interface
targetDescription.format = SLANG_GLSL;
targetDescription.profile = globalSession->findProfile("glsl_330");
// Set the session description
sessionDescription.targets = &targetDescription;
sessionDescription.targetCount = 1;
sessionDescription.searchPathCount = 0;
sessionDescription.fileSystem = &this->fileSystem;
// Create session
globalSession->createSession(sessionDescription, session.writeRef());
}
std::shared_ptr<Game> ShaderManager::getGame() {
auto game = this->game.lock();
assertNotNull(game, "Game instance must not be null.");
return game;
}
ShaderManager::~ShaderManager() {
// Clear all shaders
shaders.clear();
}

View File

@@ -5,13 +5,45 @@
#pragma once
#include "display/shader/Shader.hpp"
#include "ShaderManagerSlangFileSystem.hpp"
using namespace slang;
namespace Dawn {
class ShaderManager {
class Game;
class ShaderLoader;
class ShaderManager : public std::enable_shared_from_this<ShaderManager> {
private:
std::vector<std::shared_ptr<IShaderBase>> shaders;
std::vector<std::weak_ptr<IShaderBase>> shaders;
std::weak_ptr<Game> game;
ShaderManagerSlangFileSystem fileSystem;
Slang::ComPtr<IGlobalSession> globalSession;
TargetDesc targetDescription;
SessionDesc sessionDescription;
Slang::ComPtr<ISession> session;
public:
/**
* Creates a new shader manager.
*/
ShaderManager();
/**
* Initializes the shader manager.
*
* @param game The game instance that the shader manager is being used in.
*/
void init(const std::shared_ptr<Game> &game);
/**
* Retreives the game instance.
*
* @return Game instance.
*/
std::shared_ptr<Game> getGame();
/**
* Retreives an instance of the shader from the shader manager. If the
* shader does not exist it will be created.
@@ -23,8 +55,7 @@ namespace Dawn {
std::shared_ptr<T> getShader() {
auto itShaders = shaders.begin();
while(itShaders != shaders.end()) {
// auto shader = itShaders->lock();
auto shader = *itShaders;
auto shader = itShaders->lock();
if(!shader) {
itShaders = shaders.erase(itShaders);
continue;
@@ -44,8 +75,8 @@ namespace Dawn {
/**
* Disposes of all shaders.
*/
~ShaderManager() {
shaders.clear();
}
~ShaderManager();
friend class ShaderLoader;
};
}

View File

@@ -0,0 +1,78 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "ShaderManagerSlangFileSystem.hpp"
#include "assert/assert.hpp"
#include "display/shader/ShaderManager.hpp"
#include "game/Game.hpp"
#include "asset/loader/StringLoader.hpp"
#include "util/String.hpp"
using namespace Dawn;
void const * ShaderManagerSlangString::getBufferPointer() {
return this->str.c_str();
}
size_t ShaderManagerSlangString::getBufferSize() {
return this->str.size();
}
SlangResult ShaderManagerSlangString::queryInterface(
SlangUUID const& uuid,
void** outObject
) {
return SLANG_E_NOT_IMPLEMENTED;
}
uint32_t ShaderManagerSlangString::addRef() {
return refs++;
}
uint32_t ShaderManagerSlangString::release() {
return refs--;
}
//
SlangResult ShaderManagerSlangFileSystem::loadFile(
const char* path,
ISlangBlob** outBlob
) {
auto shaderManager = this->sm.lock();
assertNotNull(shaderManager, "ShaderManager must not be null.");
if(!String::endsWith(path, ".slang")) return SLANG_E_NOT_FOUND;
std::cout << "Loading: " << path << std::endl;
auto loader = shaderManager->getGame()->assetManager->get<StringLoader>(path);
loader->loadImmediately();
auto blob = new ShaderManagerSlangString();
blob->str = loader->data;
*outBlob = blob;
std::cout << "Loaded: " << path << std::endl;
return SLANG_OK;
}
SlangResult ShaderManagerSlangFileSystem::queryInterface(
SlangUUID const& uuid,
void** outObject
) {
return SLANG_E_NOT_IMPLEMENTED;
}
uint32_t ShaderManagerSlangFileSystem::addRef() {
return refs++;
}
uint32_t ShaderManagerSlangFileSystem::release() {
return refs--;
}
void * ShaderManagerSlangFileSystem::castAs(SlangUUID const& uuid) {
return nullptr;
}

View File

@@ -0,0 +1,46 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
#include "slang.h"
#include "slang-gfx.h"
#include "slang-com-ptr.h"
using namespace slang;
namespace Dawn {
class ShaderManager;
struct ShaderManagerSlangString : public ISlangBlob {
std::string str;
uint32_t refs = 0;
void const* getBufferPointer() override;
size_t getBufferSize() override;
SlangResult queryInterface(SlangUUID const& uuid, void** outObject) override;
uint32_t addRef() override;
uint32_t release() override;
};
struct ShaderManagerSlangFileSystem : public ISlangFileSystem {
private:
std::weak_ptr<ShaderManager> sm;
uint32_t refs = 0;
public:
SlangResult loadFile(
const char* path,
ISlangBlob** outBlob
) override;
SlangResult queryInterface(SlangUUID const& uuid, void** outObject) override;
uint32_t addRef() override;
uint32_t release() override;
void * castAs(SlangUUID const& uuid) override;
friend class ShaderManager;
};
}

View File

@@ -62,6 +62,9 @@ void IGame::init() {
settingsManager->init(selfAsGame);
settingsManager->load();
shaderManager = std::make_shared<ShaderManager>();
shaderManager->init(shared_from_this());
this->initManagers();
// TEST

View File

@@ -13,6 +13,7 @@
#include "locale/LocaleManager.hpp"
#include "save/SaveManager.hpp"
#include "settings/SettingsManager.hpp"
#include "display/shader/ShaderManager.hpp"
#ifdef DAWN_ENABLE_PHYSICS
#include "physics/PhysicsManager.hpp"
@@ -59,6 +60,7 @@ namespace Dawn {
std::shared_ptr<AssetManager> assetManager;
std::shared_ptr<LocaleManager> localeManager;
std::shared_ptr<SettingsManager> settingsManager;
std::shared_ptr<ShaderManager> shaderManager;
#ifdef DAWN_ENABLE_PHYSICS
std::shared_ptr<PhysicsManager> physicsManager;

View File

@@ -33,4 +33,13 @@ std::vector<std::string> String::split(
res.push_back(s.substr(posStart));
return res;
}
bool_t String::endsWith(const std::string &str, const std::string &needle) {
if(str.length() >= needle.length()) {
return (0 == str.compare(
str.length() - needle.length(), needle.length(), needle
));
}
return false;
}

View File

@@ -37,5 +37,14 @@ namespace Dawn {
const std::string &str,
const std::string &delim
);
/**
* Checks if the given string starts with the given needle.
*
* @param str String to check.
* @param needle String to check for.
* @return True if the string starts with the needle.
*/
static bool_t endsWith(const std::string &str, const std::string &needle);
};
}