diff --git a/Editor/Include/Editor/Widget/GraphicsSampleWidget.h b/Editor/Include/Editor/Widget/GraphicsSampleWidget.h deleted file mode 100644 index 79920ddd3..000000000 --- a/Editor/Include/Editor/Widget/GraphicsSampleWidget.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// Created by Kindem on 2025/3/16. -// - -#pragma once - -#include -#include - -#include -#include - -namespace Editor { - class GraphicsSampleWidget final : public GraphicsWidget { - Q_OBJECT - - public: - explicit GraphicsSampleWidget(QWidget* inParent = nullptr); - ~GraphicsSampleWidget() override; - - protected: - void resizeEvent(QResizeEvent* event) override; - - private: - static constexpr uint8_t swapChainTextureNum = 2; - - void RecreateSwapChain(uint32_t inWidth, uint32_t inHeight); - void DispatchFrame() const; - void DrawFrame() const; - - Common::UniquePtr imageReadySemaphore; - Common::UniquePtr renderFinishedSemaphore; - Common::UniquePtr frameFence; - Common::UniquePtr swapChain; - std::array swapChainTextures; - std::array, 2> swapChainTextureViews; - Render::ShaderCompileOutput vsCompileOutput; - Render::ShaderCompileOutput psCompileOutput; - Common::UniquePtr vsModule; - Common::UniquePtr psModule; - Common::UniquePtr bindGroupLayout; - Common::UniquePtr pipelineLayout; - Common::UniquePtr pipeline; - Common::UniquePtr vertexBuffer; - Common::UniquePtr vertexBufferView; - Common::UniquePtr uniformBuffer; - Common::UniquePtr uniformBufferView; - Common::UniquePtr bindGroup; - Common::UniquePtr commandBuffer; - Common::UniquePtr drawThread; - std::atomic_bool running; - }; -} diff --git a/Editor/Include/Editor/Widget/ProjectHub.h b/Editor/Include/Editor/Widget/ProjectHub.h index 0d864f0af..de1370326 100644 --- a/Editor/Include/Editor/Widget/ProjectHub.h +++ b/Editor/Include/Editor/Widget/ProjectHub.h @@ -26,20 +26,32 @@ namespace Editor { EProperty() std::string path; }; + struct EClass() CreateProjectResult { + EClassBody(CreateProjectResult) + + EProperty() bool success; + EProperty() std::string error; + EProperty() std::string projectPath; + }; + class ProjectHubBackend final : public QObject { Q_OBJECT Q_PROPERTY(QString engineVersion READ GetEngineVersion CONSTANT) Q_PROPERTY(QJsonValue projectTemplates READ GetProjectTemplates CONSTANT) - Q_PROPERTY(QJsonValue recentProjects READ GetRecentProjects) + Q_PROPERTY(QJsonValue recentProjects READ GetRecentProjects NOTIFY RecentProjectsChanged) public: explicit ProjectHubBackend(ProjectHub* parent = nullptr); ~ProjectHubBackend() override; public Q_SLOTS: - void CreateProject() const; + QJsonValue CreateProject(const QString& inName, const QString& inDirectory, const QString& inTemplatePath); + void OpenProject(const QString& inProjectPath); QString BrowseDirectory() const; + Q_SIGNALS: + void RecentProjectsChanged(); + private: QString GetEngineVersion() const; QJsonValue GetProjectTemplates() const; diff --git a/Editor/Include/Editor/Widget/Prototype.h b/Editor/Include/Editor/Widget/Prototype.h new file mode 100644 index 000000000..d848e0050 --- /dev/null +++ b/Editor/Include/Editor/Widget/Prototype.h @@ -0,0 +1,103 @@ +// +// Created by johnk on 2026/6/21. +// + +#pragma once + +#include +#include + +#include + +#include +#include +#include + +namespace Editor { + class PrototypeTriangleWidget final : public GraphicsWidget { + Q_OBJECT + + public: + explicit PrototypeTriangleWidget(QWidget* inParent = nullptr); + ~PrototypeTriangleWidget() override; + + void SetRotationSpeed(float inRadiansPerSecond); + float GetRotationSpeed() const; + + protected: + void resizeEvent(QResizeEvent* event) override; + + private: + static constexpr uint8_t swapChainTextureNum = 2; + + void RecreateSwapChain(uint32_t inWidth, uint32_t inHeight); + void DispatchFrame(); + void DrawFrame(); + + std::atomic rotationSpeed; + float rotation; + double lastFrameSeconds; + + Common::UniquePtr imageReadySemaphore; + Common::UniquePtr renderFinishedSemaphore; + Common::UniquePtr frameFence; + Common::UniquePtr swapChain; + std::array swapChainTextures; + std::array, swapChainTextureNum> swapChainTextureViews; + Render::ShaderCompileOutput vsCompileOutput; + Render::ShaderCompileOutput psCompileOutput; + Common::UniquePtr vsModule; + Common::UniquePtr psModule; + Common::UniquePtr bindGroupLayout; + Common::UniquePtr pipelineLayout; + Common::UniquePtr pipeline; + Common::UniquePtr vertexBuffer; + Common::UniquePtr vertexBufferView; + Common::UniquePtr uniformBuffer; + Common::UniquePtr uniformBufferView; + Common::UniquePtr bindGroup; + Common::UniquePtr commandBuffer; + Common::UniquePtr drawThread; + std::atomic_bool running; + }; + + class PrototypeBackend final : public QObject { + Q_OBJECT + Q_PROPERTY(double rotationSpeed READ GetRotationSpeed CONSTANT) + + public: + explicit PrototypeBackend(PrototypeTriangleWidget* inTriangle, QObject* inParent = nullptr); + ~PrototypeBackend() override; + + public Q_SLOTS: + void SetRotationSpeed(double inDegreesPerSecond); + + private: + double GetRotationSpeed() const; + + PrototypeTriangleWidget* triangle; + }; + + class PrototypeWebWidget final : public WebWidget { + Q_OBJECT + + public: + explicit PrototypeWebWidget(PrototypeTriangleWidget* inTriangle, QWidget* inParent = nullptr); + ~PrototypeWebWidget() override; + + private: + PrototypeBackend* backend; + }; + + class PrototypePlayground final : public QWidget { + Q_OBJECT + + public: + explicit PrototypePlayground(QWidget* inParent = nullptr); + ~PrototypePlayground() override; + + private: + PrototypeTriangleWidget* triangle; + PrototypeWebWidget* web; + }; +} diff --git a/Editor/Shader/GraphicsWindowSample.esl b/Editor/Shader/Prototype.esl similarity index 62% rename from Editor/Shader/GraphicsWindowSample.esl rename to Editor/Shader/Prototype.esl index 384503904..08f75969a 100644 --- a/Editor/Shader/GraphicsWindowSample.esl +++ b/Editor/Shader/Prototype.esl @@ -7,21 +7,27 @@ struct FragmentInput { #if VERTEX_SHADER cbuffer vsUniform { - float3 vertexColor; + float rotation; }; FragmentInput VSMain( uint vertexId : SV_VertexID, VkLocation(0) float3 position : POSITION) { + const float sinR = sin(rotation); + const float cosR = cos(rotation); + const float2 rotated = float2( + position.x * cosR - position.y * sinR, + position.x * sinR + position.y * cosR); + FragmentInput fragmentInput; - fragmentInput.position = float4(position.xyz, 1.0f); + fragmentInput.position = float4(rotated, position.z, 1.0f); #if VULKAN fragmentInput.position.y = - fragmentInput.position.y; #endif fragmentInput.color = float4(0.0f, 0.0f, 0.0f, 1.0f); - fragmentInput.color[vertexId % 3] = vertexColor[vertexId % 3]; + fragmentInput.color[vertexId % 3] = 1.0f; return fragmentInput; } #endif diff --git a/Editor/Src/Main.cpp b/Editor/Src/Main.cpp index 3ff35e2d1..4feceea18 100644 --- a/Editor/Src/Main.cpp +++ b/Editor/Src/Main.cpp @@ -9,15 +9,12 @@ #include #include #include +#include #include -#if BUILD_CONFIG_DEBUG -#include - -static Core::CmdlineArgValue caGraphicsSample( - "graphicsSample", "-graphicsSample", false, - "Whether to run graphics sample instead of editor"); -#endif +static Core::CmdlineArgValue caPrototype( + "prototype", "-prototype", false, + "Whether to run the prototype playground (native graphics widget mixed with web widget) instead of editor"); static Core::CmdlineArgValue caRhiType( "rhiType", "-rhi", RHI::GetPlatformDefaultRHIAbbrString(), @@ -28,9 +25,7 @@ static Core::CmdlineArgValue caProjectRoot( "project root path"); enum class EditorApplicationModel : uint8_t { -#if BUILD_CONFIG_DEBUG - graphicsSample, -#endif + prototype, projectHub, editor, max @@ -38,11 +33,9 @@ enum class EditorApplicationModel : uint8_t { static EditorApplicationModel GetAppModel() { -#if BUILD_CONFIG_DEBUG - if (caGraphicsSample.GetValue()) { - return EditorApplicationModel::graphicsSample; + if (caPrototype.GetValue()) { + return EditorApplicationModel::prototype; } -#endif if (caProjectRoot.GetValue().empty()) { return EditorApplicationModel::projectHub; } @@ -51,11 +44,8 @@ static EditorApplicationModel GetAppModel() static bool NeedInitCore(EditorApplicationModel inModel) { - bool result = inModel == EditorApplicationModel::editor; -#if BUILD_CONFIG_DEBUG - result = result || inModel == EditorApplicationModel::graphicsSample; -#endif - return result; + return inModel == EditorApplicationModel::editor + || inModel == EditorApplicationModel::prototype; } static void InitializePreQtApp(EditorApplicationModel inModel) @@ -91,11 +81,9 @@ static void Cleanup(EditorApplicationModel inModel) static Common::UniquePtr CreateMainWidget(EditorApplicationModel inModel) { -#if BUILD_CONFIG_DEBUG - if (inModel == EditorApplicationModel::graphicsSample) { - return new Editor::GraphicsSampleWidget(); + if (inModel == EditorApplicationModel::prototype) { + return new Editor::PrototypePlayground(); } -#endif if (inModel == EditorApplicationModel::projectHub) { // NOLINT return new Editor::ProjectHub(); } diff --git a/Editor/Src/Widget/ProjectHub.cpp b/Editor/Src/Widget/ProjectHub.cpp index b081d4f41..8bfbd3907 100644 --- a/Editor/Src/Widget/ProjectHub.cpp +++ b/Editor/Src/Widget/ProjectHub.cpp @@ -2,6 +2,8 @@ // Created by johnk on 2025/8/3. // +#include + #include #include @@ -10,8 +12,63 @@ #include #include #include +#include +#include +#include #include +namespace Editor::Internal { + constexpr std::string_view templateFileExtension = ".tpl"; + constexpr std::string_view cmakeMinVersion = "3.25"; + + static Common::Path StripTemplateExtension(const Common::Path& inRelativePath) + { + const std::string str = inRelativePath.String(); + return { str.substr(0, str.size() - templateFileExtension.size()) }; + } + + static QJsonValue ToJsonValue(const CreateProjectResult& inResult) + { + QJsonValue value; + QtJsonSerialize(value, inResult); + return value; + } + + static Common::Result RenderProjectTemplate( + const Common::Path& inTemplateDir, const Common::Path& inProjectDir, const std::string& inProjectName) + { + Common::TemplateEngine templateEngine; + templateEngine + .Set("projectName", inProjectName) + .Set("cmakeMinVersion", std::string(cmakeMinVersion)); + + Common::Result result = Common::Ok(); + inTemplateDir.TraverseRecurse([&](const Common::Path& inPath) -> bool { + if (inPath.IsDirectory()) { + return true; + } + + const Common::Path relativePath = inPath.Relative(inTemplateDir); + const std::string extension = inPath.Extension(); + const bool isTemplate = std::string_view(extension) == templateFileExtension; + const Common::Path dstPath = inProjectDir / (isTemplate ? StripTemplateExtension(relativePath) : relativePath); + dstPath.Parent().MakeDir(); + + if (!isTemplate) { + inPath.CopyTo(dstPath); + return true; + } + if (auto renderResult = templateEngine.RenderFileTo(inPath.String(), dstPath.String()); + renderResult.IsErr()) { + result = Common::Err(renderResult.Error()); + return false; + } + return true; + }); + return result; + } +} + namespace Editor { ProjectHubBackend::ProjectHubBackend(ProjectHub* parent) : QObject(parent) @@ -37,10 +94,43 @@ namespace Editor { Common::JsonSerializeToFile(recentProjectsFile.String(), recentProjects); } - void ProjectHubBackend::CreateProject() const + QJsonValue ProjectHubBackend::CreateProject(const QString& inName, const QString& inDirectory, const QString& inTemplatePath) + { + const std::string name = inName.toStdString(); + const std::string directory = inDirectory.toStdString(); + const std::string templatePath = inTemplatePath.toStdString(); + + if (name.empty() || directory.empty() || templatePath.empty()) { + return Internal::ToJsonValue({ .success = false, .error = "Project name, directory and template must not be empty.", .projectPath = {} }); + } + + const Common::Path templateDir(templatePath); + if (!templateDir.Exists() || !templateDir.IsDirectory()) { + return Internal::ToJsonValue({ .success = false, .error = std::format("Project template '{}' does not exist.", templatePath), .projectPath = {} }); + } + + const Common::Path projectDir = Common::Path(directory) / name; + if (projectDir.Exists()) { + return Internal::ToJsonValue({ .success = false, .error = std::format("Target directory '{}' already exists.", projectDir.String()), .projectPath = {} }); + } + + if (const auto result = Internal::RenderProjectTemplate(templateDir, projectDir, name); + result.IsErr()) { + return Internal::ToJsonValue({ .success = false, .error = result.Error(), .projectPath = {} }); + } + + recentProjects.emplace_back(RecentProjectInfo { name, projectDir.String() }); + Common::JsonSerializeToFile(recentProjectsFile.String(), recentProjects); + emit RecentProjectsChanged(); + + LogInfo(ProjectHub, "created project '{}' at '{}'", name, projectDir.String()); + return Internal::ToJsonValue({ .success = true, .error = {}, .projectPath = projectDir.String() }); + } + + void ProjectHubBackend::OpenProject(const QString& inProjectPath) // NOLINT { - // TODO - LogInfo(ProjectHub, "ProjectHubBridge::CreateProject"); + // TODO: launch the editor for the project at inProjectPath + LogInfo(ProjectHub, "open project '{}'", inProjectPath.toStdString()); } QString ProjectHubBackend::BrowseDirectory() const // NOLINT diff --git a/Editor/Src/Widget/GraphicsSampleWidget.cpp b/Editor/Src/Widget/Prototype.cpp similarity index 67% rename from Editor/Src/Widget/GraphicsSampleWidget.cpp rename to Editor/Src/Widget/Prototype.cpp index 0148b8de9..c202d5e0e 100644 --- a/Editor/Src/Widget/GraphicsSampleWidget.cpp +++ b/Editor/Src/Widget/Prototype.cpp @@ -1,52 +1,75 @@ // -// Created by Kindem on 2025/3/16. +// Created by johnk on 2026/6/21. // +#include + #include +#include #include -#include -#include // NOLINT - -namespace Editor { - struct GraphicsWindowSampleVertex { +#include +#include +#include // NOLINT + +// In a unity build may be pulled in by an earlier translation unit after RHI's own headers were already +// included (and thus their `#undef CreateSemaphore` skipped via #pragma once), leaving the Win32 `CreateSemaphore` +// macro active. Drop it so the RHI::Device::CreateSemaphore() calls below resolve to the real method. +#undef CreateSemaphore + +namespace Editor::Internal { + constexpr float pi = 3.14159265358979323846f; + constexpr float twoPi = 2.0f * pi; + constexpr float degToRad = pi / 180.0f; + constexpr float radToDeg = 180.0f / pi; + constexpr float defaultRotationSpeedDegrees = 90.0f; + + struct PrototypeVertex { Common::FVec3 position; }; - struct GraphicsWindowSampleVsUniform { - Common::FVec3 color; + struct PrototypeVsUniform { + float rotation; + float padding0; + float padding1; + float padding2; }; +} - GraphicsSampleWidget::GraphicsSampleWidget(QWidget* inParent) +namespace Editor { + PrototypeTriangleWidget::PrototypeTriangleWidget(QWidget* inParent) : GraphicsWidget(inParent) + , rotationSpeed(Internal::defaultRotationSpeedDegrees * Internal::degToRad) + , rotation(0.0f) + , lastFrameSeconds(-1.0) , imageReadySemaphore(GetDevice().CreateSemaphore()) , renderFinishedSemaphore(GetDevice().CreateSemaphore()) , frameFence(GetDevice().CreateFence(true)) - , drawThread(Common::MakeUnique("DrawThread")) + , drawThread(Common::MakeUnique("PrototypeDrawThread")) { - resize(1024, 768); + setMinimumSize(320, 240); + resize(640, 480); RecreateSwapChain(width(), height()); Render::ShaderCompileOptions shaderCompileOptions; - shaderCompileOptions.includeDirectories = {"../Shader/Engine"}; shaderCompileOptions.byteCodeType = GetDevice().GetGpu().GetInstance().GetRHIType() == RHI::RHIType::directX12 ? Render::ShaderByteCodeType::dxil : Render::ShaderByteCodeType::spirv; shaderCompileOptions.withDebugInfo = static_cast(BUILD_CONFIG_DEBUG); // NOLINT { Render::ShaderCompileInput shaderCompileInput; - shaderCompileInput.source = Common::FileUtils::ReadTextFile("../Shader/Editor/GraphicsWindowSample.esl").Unwrap(); + shaderCompileInput.source = Common::FileUtils::ReadTextFile("../Shader/Editor/Prototype.esl").Unwrap(); shaderCompileInput.stage = RHI::ShaderStageBits::sVertex; shaderCompileInput.entryPoint = "VSMain"; - shaderCompileInput.includeDirectories.emplace_back("../Test/Sample/ShaderInclude"); + shaderCompileInput.includeDirectories.emplace_back("../Shader/Explosion"); vsCompileOutput = Render::ShaderCompiler::Get().Compile(shaderCompileInput, shaderCompileOptions).get(); } { Render::ShaderCompileInput shaderCompileInput; - shaderCompileInput.source = Common::FileUtils::ReadTextFile("../Shader/Editor/GraphicsWindowSample.esl").Unwrap(); + shaderCompileInput.source = Common::FileUtils::ReadTextFile("../Shader/Editor/Prototype.esl").Unwrap(); shaderCompileInput.stage = RHI::ShaderStageBits::sPixel; shaderCompileInput.entryPoint = "PSMain"; - shaderCompileInput.includeDirectories.emplace_back("../Test/Sample/ShaderInclude"); + shaderCompileInput.includeDirectories.emplace_back("../Shader/Explosion"); psCompileOutput = Render::ShaderCompiler::Get().Compile(shaderCompileInput, shaderCompileOptions).get(); } @@ -68,7 +91,7 @@ namespace Editor { .SetVertexState( RHI::VertexState() .AddVertexBufferLayout( - RHI::VertexBufferLayout(RHI::VertexStepMode::perVertex, sizeof(GraphicsWindowSampleVertex)) + RHI::VertexBufferLayout(RHI::VertexStepMode::perVertex, sizeof(Internal::PrototypeVertex)) .AddAttribute(RHI::VertexAttribute(vsCompileOutput.reflectionData.QueryVertexBindingChecked("POSITION"), RHI::VertexFormat::float32X3, 0)))) .SetFragmentState( RHI::FragmentState() @@ -76,12 +99,12 @@ namespace Editor { .SetPrimitiveState(RHI::PrimitiveState(RHI::PrimitiveTopologyType::triangle, RHI::FillMode::solid, RHI::IndexFormat::uint16, RHI::FrontFace::ccw, RHI::CullMode::none))); { - const std::vector vertices = { + const std::vector vertices = { {{-.5f, -.5f, 0.f}}, {{.5f, -.5f, 0.f}}, {{0.f, .5f, 0.f}}, }; - const auto bufferSize = vertices.size() * sizeof(GraphicsWindowSampleVertex); + const auto bufferSize = vertices.size() * sizeof(Internal::PrototypeVertex); vertexBuffer = GetDevice().CreateBuffer( RHI::BufferCreateInfo() @@ -92,20 +115,20 @@ namespace Editor { auto* data = vertexBuffer->Map(RHI::MapMode::write, 0, bufferSize); memcpy(data, vertices.data(), bufferSize); - vertexBuffer->UnMap(); + vertexBuffer->Unmap(); vertexBufferView = vertexBuffer->CreateBufferView( RHI::BufferViewCreateInfo() .SetType(RHI::BufferViewType::vertex) .SetSize(bufferSize) .SetOffset(0) - .SetExtendVertex(sizeof(GraphicsWindowSampleVertex))); + .SetExtendVertex(sizeof(Internal::PrototypeVertex))); } { uniformBuffer = GetDevice().CreateBuffer( RHI::BufferCreateInfo() - .SetSize(sizeof(GraphicsWindowSampleVsUniform)) + .SetSize(sizeof(Internal::PrototypeVsUniform)) .SetUsages(RHI::BufferUsageBits::uniform | RHI::BufferUsageBits::mapWrite | RHI::BufferUsageBits::copySrc) .SetInitialState(RHI::BufferState::staging) .SetDebugName("vsUniform")); @@ -113,7 +136,7 @@ namespace Editor { uniformBufferView = uniformBuffer->CreateBufferView( RHI::BufferViewCreateInfo() .SetType(RHI::BufferViewType::uniformBinding) - .SetSize(sizeof(GraphicsWindowSampleVsUniform)) + .SetSize(sizeof(Internal::PrototypeVsUniform)) .SetOffset(0)); } @@ -127,14 +150,24 @@ namespace Editor { DispatchFrame(); } - GraphicsSampleWidget::~GraphicsSampleWidget() + PrototypeTriangleWidget::~PrototypeTriangleWidget() { running = false; drawThread.Reset(); WaitDeviceIdle(); } - void GraphicsSampleWidget::resizeEvent(QResizeEvent* event) + void PrototypeTriangleWidget::SetRotationSpeed(float inRadiansPerSecond) + { + rotationSpeed.store(inRadiansPerSecond); + } + + float PrototypeTriangleWidget::GetRotationSpeed() const + { + return rotationSpeed.load(); + } + + void PrototypeTriangleWidget::resizeEvent(QResizeEvent* event) { GraphicsWidget::resizeEvent(event); @@ -143,7 +176,7 @@ namespace Editor { }); } - void GraphicsSampleWidget::RecreateSwapChain(uint32_t inWidth, uint32_t inHeight) + void PrototypeTriangleWidget::RecreateSwapChain(uint32_t inWidth, uint32_t inHeight) { static std::vector formatQualifiers = { RHI::PixelFormat::rgba8Unorm, @@ -186,7 +219,7 @@ namespace Editor { } } - void GraphicsSampleWidget::DispatchFrame() const + void PrototypeTriangleWidget::DispatchFrame() { if (!running) { return; @@ -194,20 +227,22 @@ namespace Editor { drawThread->EmplaceTask([this]() -> void { DrawFrame(); }); } - void GraphicsSampleWidget::DrawFrame() const + void PrototypeTriangleWidget::DrawFrame() { frameFence->Wait(); frameFence->Reset(); const double currentTimeSeconds = Common::TimePoint::Now().ToSeconds(); - const GraphicsWindowSampleVsUniform uniform = {{ - (std::sin(currentTimeSeconds) + 1) / 2, - (std::cos(currentTimeSeconds) + 1) / 2, - std::abs(std::sin(currentTimeSeconds)) - }}; - auto* uniformData = uniformBuffer->Map(RHI::MapMode::write, 0, sizeof(GraphicsWindowSampleVsUniform)); - memcpy(uniformData, &uniform, sizeof(GraphicsWindowSampleVsUniform)); - uniformBuffer->UnMap(); + if (lastFrameSeconds >= 0.0) { + rotation += static_cast(currentTimeSeconds - lastFrameSeconds) * rotationSpeed.load(); + rotation = std::fmod(rotation, Internal::twoPi); + } + lastFrameSeconds = currentTimeSeconds; + + const Internal::PrototypeVsUniform uniform { rotation, 0.0f, 0.0f, 0.0f }; + auto* uniformData = uniformBuffer->Map(RHI::MapMode::write, 0, sizeof(Internal::PrototypeVsUniform)); + memcpy(uniformData, &uniform, sizeof(Internal::PrototypeVsUniform)); + uniformBuffer->Unmap(); const auto backTextureIndex = swapChain->AcquireBackTexture(imageReadySemaphore.Get()); const Common::UniquePtr commandRecorder = commandBuffer->Begin(); @@ -240,4 +275,50 @@ namespace Editor { DispatchFrame(); } + + PrototypeBackend::PrototypeBackend(PrototypeTriangleWidget* inTriangle, QObject* inParent) + : QObject(inParent) + , triangle(inTriangle) + { + } + + PrototypeBackend::~PrototypeBackend() = default; + + void PrototypeBackend::SetRotationSpeed(double inDegreesPerSecond) + { + triangle->SetRotationSpeed(static_cast(inDegreesPerSecond) * Internal::degToRad); + } + + double PrototypeBackend::GetRotationSpeed() const + { + return static_cast(triangle->GetRotationSpeed() * Internal::radToDeg); + } + + PrototypeWebWidget::PrototypeWebWidget(PrototypeTriangleWidget* inTriangle, QWidget* inParent) + : WebWidget(inParent) + { + backend = new PrototypeBackend(inTriangle, this); + GetWebChannel()->registerObject("backend", backend); + Load("/prototype"); + } + + PrototypeWebWidget::~PrototypeWebWidget() = default; + + PrototypePlayground::PrototypePlayground(QWidget* inParent) + : QWidget(inParent) + { + setWindowTitle("Explosion Prototype Playground"); + resize(1280, 720); + + triangle = new PrototypeTriangleWidget(this); + web = new PrototypeWebWidget(triangle, this); + + auto* layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(triangle, 1); + layout->addWidget(web, 1); + } + + PrototypePlayground::~PrototypePlayground() = default; } // namespace Editor diff --git a/Editor/Web/src/App.tsx b/Editor/Web/src/App.tsx index baf24637d..6c3d38191 100644 --- a/Editor/Web/src/App.tsx +++ b/Editor/Web/src/App.tsx @@ -1,10 +1,12 @@ import { Route, Routes } from 'react-router-dom'; import ProjectHubPage from '@/pages/project-hub'; +import PrototypePage from '@/pages/prototype'; function App() { return ( } path='/project-hub' /> + } path='/prototype' /> ); } diff --git a/Editor/Web/src/pages/project-hub.tsx b/Editor/Web/src/pages/project-hub.tsx index 2dae091ca..f03f68fa3 100644 --- a/Editor/Web/src/pages/project-hub.tsx +++ b/Editor/Web/src/pages/project-hub.tsx @@ -8,7 +8,7 @@ import { Chip } from '@heroui/chip'; import { Listbox, ListboxItem } from '@heroui/listbox'; import { Avatar } from '@heroui/avatar'; import { ScrollShadow } from '@heroui/scroll-shadow'; -import { Select, SelectItem } from '@heroui/react'; +import { Select, SelectItem, addToast } from '@heroui/react'; import { QWebChannel } from '@/qwebchannel'; interface RecentProjectInfo { @@ -21,11 +21,20 @@ interface ProjectTemplateInfo { path: string; } +interface CreateProjectResult { + success: boolean; + error: string; + projectPath: string; +} + export default function ProjectHubPage() { const [engineVersion, setEngineVersion] = useState(''); const [recentProjects, setRecentProjects] = useState(Array); const [projectTemplates, setProjectTemplates] = useState(Array); + const [projectName, setProjectName] = useState(''); const [projectPath, setProjectPath] = useState(''); + const [projectTemplate, setProjectTemplate] = useState('0'); + const [isCreating, setIsCreating] = useState(false); useEffect(() => { new QWebChannel(window.qt.webChannelTransport, (channel: QWebChannel): void => { @@ -33,19 +42,40 @@ export default function ProjectHubPage() { setEngineVersion(window.backend.engineVersion); setRecentProjects(window.backend.recentProjects); setProjectTemplates(window.backend.projectTemplates); + window.backend.RecentProjectsChanged.connect(() => { + setRecentProjects(window.backend.recentProjects); + }); }); }, []); function onCreateProject(): void { - // TODO - console.error("onCreateProject()"); - window.backend.CreateProject(); + const template = projectTemplates[parseInt(projectTemplate)]; + if (!projectName || !projectPath || !template) { + addToast({ title: 'Cannot create project', description: 'Please fill in the project name, path and template.', color: 'warning' }); + return; + } + + setIsCreating(true); + window.backend.CreateProject(projectName, projectPath, template.path, (result: CreateProjectResult) => { + setIsCreating(false); + if (!result.success) { + addToast({ title: 'Failed to create project', description: result.error, color: 'danger' }); + return; + } + addToast({ title: 'Project created', description: `${projectName} has been created.`, color: 'success' }); + setProjectName(''); + setProjectPath(''); + openProject(result.projectPath); + }); } function onOpenProject(e: PressEvent): void { - // TODO const index = parseInt(e.target.getAttribute('data-key') as string); - console.error('onOpenProject:', index); + openProject(recentProjects[index].path); + } + + function openProject(path: string): void { + window.backend.OpenProject(path); } function onBrowseProjectPath(): void { @@ -92,19 +122,26 @@ export default function ProjectHubPage() {
- +
- +
- setProjectTemplate(Array.from(keys as Set)[0] ?? '0')} + > {projectTemplates.map((item, i) => ( {item.name} ))} - diff --git a/Editor/Web/src/pages/prototype.tsx b/Editor/Web/src/pages/prototype.tsx new file mode 100644 index 000000000..968f78810 --- /dev/null +++ b/Editor/Web/src/pages/prototype.tsx @@ -0,0 +1,75 @@ +import { useEffect, useState } from 'react'; +import { Card, CardBody, CardHeader, Slider, Button, Chip } from '@heroui/react'; +import { QWebChannel } from '@/qwebchannel'; + +const minRotationSpeed = -360; +const maxRotationSpeed = 360; + +export default function PrototypePage() { + const [ready, setReady] = useState(false); + const [rotationSpeed, setRotationSpeed] = useState(90); + + useEffect(() => { + new QWebChannel(window.qt.webChannelTransport, (channel: QWebChannel): void => { + window.backend = channel.objects.backend; + setRotationSpeed(window.backend.rotationSpeed); + setReady(true); + }); + }, []); + + function onRotationSpeedChange(value: number | number[]): void { + const speed = Array.isArray(value) ? value[0] : value; + setRotationSpeed(speed); + if (ready) { + window.backend.SetRotationSpeed(speed); + } + } + + return ( +
+
+ Prototype Playground + + native graphics + web + +
+ + + + Triangle Rotation + + {Math.round(rotationSpeed)} °/s + + + + `${v} °/s`} + maxValue={maxRotationSpeed} + minValue={minRotationSpeed} + step={1} + value={rotationSpeed} + onChange={onRotationSpeedChange} + /> +
+ + + +
+
+
+ +

+ The triangle on the left is rendered through the native graphics API (RHI). This panel is a web widget; both + live inside the same Qt layout. +

+
+ ); +} diff --git a/Editor/Web/src/provider.tsx b/Editor/Web/src/provider.tsx index 2f42bec60..f9c2c0541 100644 --- a/Editor/Web/src/provider.tsx +++ b/Editor/Web/src/provider.tsx @@ -1,5 +1,6 @@ import type { NavigateOptions } from 'react-router-dom'; import { HeroUIProvider } from '@heroui/system'; +import { ToastProvider } from '@heroui/react'; import { useHref, useNavigate } from 'react-router-dom'; declare module '@react-types/shared' { @@ -13,6 +14,7 @@ export function Provider({ children }: { children: React.ReactNode }) { return ( + {children} ); diff --git a/Engine/Source/RHI-DirectX12/Include/RHI/DirectX12/Buffer.h b/Engine/Source/RHI-DirectX12/Include/RHI/DirectX12/Buffer.h index d386c5bf2..b9b22d10a 100644 --- a/Engine/Source/RHI-DirectX12/Include/RHI/DirectX12/Buffer.h +++ b/Engine/Source/RHI-DirectX12/Include/RHI/DirectX12/Buffer.h @@ -21,7 +21,7 @@ namespace RHI::DirectX12 { ~DX12Buffer() override; void* Map(MapMode inMapMode, size_t inOffset, size_t inLength) override; - void UnMap() override; + void Unmap() override; Common::UniquePtr CreateBufferView(const BufferViewCreateInfo& inCreateInfo) override; ID3D12Resource* GetNative() const; diff --git a/Engine/Source/RHI-DirectX12/Include/RHI/DirectX12/CommandRecorder.h b/Engine/Source/RHI-DirectX12/Include/RHI/DirectX12/CommandRecorder.h index 1d9d94000..0b583ebb9 100644 --- a/Engine/Source/RHI-DirectX12/Include/RHI/DirectX12/CommandRecorder.h +++ b/Engine/Source/RHI-DirectX12/Include/RHI/DirectX12/CommandRecorder.h @@ -36,7 +36,7 @@ namespace RHI::DirectX12 { explicit DX12CopyPassCommandRecorder(DX12Device& inDevice, DX12CommandRecorder& inCmdRecorder, DX12CommandBuffer& inCmdBuffer); ~DX12CopyPassCommandRecorder() override; - // CommandCommandRecorder + // CommonCommandRecorder void ResourceBarrier(const Barrier& inBarrier) override; // CopyPassCommandRecorder @@ -58,7 +58,7 @@ namespace RHI::DirectX12 { explicit DX12ComputePassCommandRecorder(DX12Device& inDevice, DX12CommandRecorder& inCmdRecorder, DX12CommandBuffer& inCmdBuffer); ~DX12ComputePassCommandRecorder() override; - // CommandCommandRecorder + // CommonCommandRecorder void ResourceBarrier(const Barrier& inBarrier) override; // ComputePassCommandRecorder @@ -80,7 +80,7 @@ namespace RHI::DirectX12 { explicit DX12RasterPassCommandRecorder(DX12Device& inDevice, DX12CommandRecorder& inCmdRecorder, DX12CommandBuffer& inCmdBuffer, const RasterPassBeginInfo& inBeginInfo); ~DX12RasterPassCommandRecorder() override; - // CommandCommandRecorder + // CommonCommandRecorder void ResourceBarrier(const Barrier& inBarrier) override; // RasterPassCommandRecorder diff --git a/Engine/Source/RHI-DirectX12/Include/RHI/DirectX12/Common.h b/Engine/Source/RHI-DirectX12/Include/RHI/DirectX12/Common.h index 9feae4cc4..295daae16 100644 --- a/Engine/Source/RHI-DirectX12/Include/RHI/DirectX12/Common.h +++ b/Engine/Source/RHI-DirectX12/Include/RHI/DirectX12/Common.h @@ -197,8 +197,8 @@ namespace RHI::DirectX12 { ECIMPL_BEGIN(BlendOp, D3D12_BLEND_OP) ECIMPL_ITEM(BlendOp::opAdd, D3D12_BLEND_OP_ADD) - ECIMPL_ITEM(BlendOp::opSubstract, D3D12_BLEND_OP_SUBTRACT) - ECIMPL_ITEM(BlendOp::opReverseSubstract, D3D12_BLEND_OP_REV_SUBTRACT) + ECIMPL_ITEM(BlendOp::opSubtract, D3D12_BLEND_OP_SUBTRACT) + ECIMPL_ITEM(BlendOp::opReverseSubtract, D3D12_BLEND_OP_REV_SUBTRACT) ECIMPL_ITEM(BlendOp::opMin, D3D12_BLEND_OP_MIN) ECIMPL_ITEM(BlendOp::opMax, D3D12_BLEND_OP_MAX) ECIMPL_END(D3D12_BLEND_OP) diff --git a/Engine/Source/RHI-DirectX12/Src/Buffer.cpp b/Engine/Source/RHI-DirectX12/Src/Buffer.cpp index ecadb4c21..4d25b5957 100644 --- a/Engine/Source/RHI-DirectX12/Src/Buffer.cpp +++ b/Engine/Source/RHI-DirectX12/Src/Buffer.cpp @@ -83,7 +83,7 @@ namespace RHI::DirectX12 { return data; } - void DX12Buffer::UnMap() + void DX12Buffer::Unmap() { nativeResource->Unmap(0, nullptr); } diff --git a/Engine/Source/RHI-Dummy/Include/RHI/Dummy/Buffer.h b/Engine/Source/RHI-Dummy/Include/RHI/Dummy/Buffer.h index 58c779d30..763b2caa1 100644 --- a/Engine/Source/RHI-Dummy/Include/RHI/Dummy/Buffer.h +++ b/Engine/Source/RHI-Dummy/Include/RHI/Dummy/Buffer.h @@ -15,7 +15,7 @@ namespace RHI::Dummy { ~DummyBuffer() override; void* Map(MapMode mapMode, size_t offset, size_t length) override; - void UnMap() override; + void Unmap() override; Common::UniquePtr CreateBufferView(const BufferViewCreateInfo& createInfo) override; private: std::vector dummyData; diff --git a/Engine/Source/RHI-Dummy/Include/RHI/Dummy/CommandRecorder.h b/Engine/Source/RHI-Dummy/Include/RHI/Dummy/CommandRecorder.h index b1c983ab4..c45d52891 100644 --- a/Engine/Source/RHI-Dummy/Include/RHI/Dummy/CommandRecorder.h +++ b/Engine/Source/RHI-Dummy/Include/RHI/Dummy/CommandRecorder.h @@ -31,7 +31,7 @@ namespace RHI::Dummy { explicit DummyCopyPassCommandRecorder(const DummyCommandBuffer& dummyCommandBuffer); ~DummyCopyPassCommandRecorder() override; - // CommandCommandRecorder + // CommonCommandRecorder void ResourceBarrier(const RHI::Barrier& barrier) override; // CopyPassCommandRecorder @@ -48,7 +48,7 @@ namespace RHI::Dummy { explicit DummyComputePassCommandRecorder(const DummyCommandBuffer& dummyCommandBuffer); ~DummyComputePassCommandRecorder() override; - // CommandCommandRecorder + // CommonCommandRecorder void ResourceBarrier(const RHI::Barrier& barrier) override; // ComputePassCommandRecorder @@ -64,7 +64,7 @@ namespace RHI::Dummy { explicit DummyRasterPassCommandRecorder(const DummyCommandBuffer& dummyCommandBuffer); ~DummyRasterPassCommandRecorder() override; - // CommandCommandRecorder + // CommonCommandRecorder void ResourceBarrier(const RHI::Barrier& barrier) override; // RasterPassCommandRecorder diff --git a/Engine/Source/RHI-Dummy/Src/Buffer.cpp b/Engine/Source/RHI-Dummy/Src/Buffer.cpp index 2530cec0f..7131d7e57 100644 --- a/Engine/Source/RHI-Dummy/Src/Buffer.cpp +++ b/Engine/Source/RHI-Dummy/Src/Buffer.cpp @@ -19,7 +19,7 @@ namespace RHI::Dummy { return dummyData.data(); } - void DummyBuffer::UnMap() + void DummyBuffer::Unmap() { } diff --git a/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Buffer.h b/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Buffer.h index 5f7dda84c..f3586f4e9 100644 --- a/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Buffer.h +++ b/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Buffer.h @@ -20,7 +20,7 @@ namespace RHI::Vulkan { ~VulkanBuffer() override; void* Map(MapMode inMapMode, size_t inOffset, size_t inLength) override; - void UnMap() override; + void Unmap() override; Common::UniquePtr CreateBufferView(const BufferViewCreateInfo& inCreateInfo) override; VkBuffer GetNative() const; diff --git a/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/CommandRecorder.h b/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/CommandRecorder.h index 31c5deb51..cdad3f566 100644 --- a/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/CommandRecorder.h +++ b/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/CommandRecorder.h @@ -38,7 +38,7 @@ namespace RHI::Vulkan { explicit VulkanCopyPassCommandRecorder(VulkanDevice& inDevice, VulkanCommandRecorder& inCmdRecorder, VulkanCommandBuffer& inCmdBuffer); ~VulkanCopyPassCommandRecorder() override; - // CommandCommandRecorder + // CommonCommandRecorder void ResourceBarrier(const Barrier& inBarrier) override; // CopyPassCommandRecorder @@ -60,7 +60,7 @@ namespace RHI::Vulkan { explicit VulkanComputePassCommandRecorder(VulkanDevice& inDevice, VulkanCommandRecorder& inCmdRecorder, VulkanCommandBuffer& inCmdBuffer); ~VulkanComputePassCommandRecorder() override; - // CommandCommandRecorder + // CommonCommandRecorder void ResourceBarrier(const Barrier& inBarrier) override; // ComputePassCommandRecorder @@ -82,7 +82,7 @@ namespace RHI::Vulkan { explicit VulkanRasterPassCommandRecorder(VulkanDevice& inDevice, VulkanCommandRecorder& inCmdRecorder, VulkanCommandBuffer& inCmdBuffer, const RasterPassBeginInfo& inBeginInfo); ~VulkanRasterPassCommandRecorder() override; - // CommandCommandRecorder + // CommonCommandRecorder void ResourceBarrier(const Barrier& inBarrier) override; // RasterPassCommandRecorder diff --git a/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Common.h b/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Common.h index 20316fcb1..105f980c6 100644 --- a/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Common.h +++ b/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Common.h @@ -134,8 +134,8 @@ namespace RHI::Vulkan { ECIMPL_BEGIN(BlendOp, VkBlendOp) ECIMPL_ITEM(BlendOp::opAdd, VK_BLEND_OP_ADD) - ECIMPL_ITEM(BlendOp::opSubstract, VK_BLEND_OP_SUBTRACT) - ECIMPL_ITEM(BlendOp::opReverseSubstract, VK_BLEND_OP_REVERSE_SUBTRACT) + ECIMPL_ITEM(BlendOp::opSubtract, VK_BLEND_OP_SUBTRACT) + ECIMPL_ITEM(BlendOp::opReverseSubtract, VK_BLEND_OP_REVERSE_SUBTRACT) ECIMPL_ITEM(BlendOp::opMin, VK_BLEND_OP_MIN) ECIMPL_ITEM(BlendOp::opMax, VK_BLEND_OP_MAX) ECIMPL_END(VkBlendOp) diff --git a/Engine/Source/RHI-Vulkan/Src/Buffer.cpp b/Engine/Source/RHI-Vulkan/Src/Buffer.cpp index ffd8456b7..eba554e02 100644 --- a/Engine/Source/RHI-Vulkan/Src/Buffer.cpp +++ b/Engine/Source/RHI-Vulkan/Src/Buffer.cpp @@ -35,7 +35,7 @@ namespace RHI::Vulkan { return data; } - void VulkanBuffer::UnMap() + void VulkanBuffer::Unmap() { vmaUnmapMemory(device.GetNativeAllocator(), nativeAllocation); } diff --git a/Engine/Source/RHI/Include/RHI/Buffer.h b/Engine/Source/RHI/Include/RHI/Buffer.h index f4d7443cf..77f5320bf 100644 --- a/Engine/Source/RHI/Include/RHI/Buffer.h +++ b/Engine/Source/RHI/Include/RHI/Buffer.h @@ -26,8 +26,6 @@ namespace RHI { BufferCreateInfo& SetInitialState(BufferState inState); BufferCreateInfo& SetDebugName(std::string inDebugName); - uint64_t Hash() const; - bool operator==(const BufferCreateInfo& rhs) const; }; @@ -38,7 +36,7 @@ namespace RHI { const BufferCreateInfo& GetCreateInfo() const; virtual void* Map(MapMode mapMode, size_t offset, size_t length) = 0; - virtual void UnMap() = 0; + virtual void Unmap() = 0; virtual Common::UniquePtr CreateBufferView(const BufferViewCreateInfo& createInfo) = 0; protected: diff --git a/Engine/Source/RHI/Include/RHI/BufferView.h b/Engine/Source/RHI/Include/RHI/BufferView.h index 264bce3d6..f3c0296ec 100644 --- a/Engine/Source/RHI/Include/RHI/BufferView.h +++ b/Engine/Source/RHI/Include/RHI/BufferView.h @@ -8,7 +8,6 @@ #include #include -#include #include namespace RHI { @@ -48,8 +47,6 @@ namespace RHI { BufferViewCreateInfo& SetExtendVertex(uint32_t inStride); BufferViewCreateInfo& SetExtendIndex(IndexFormat inFormat); BufferViewCreateInfo& SetExtendStorage(uint32_t inStride); - - uint64_t Hash() const; }; class BufferView { diff --git a/Engine/Source/RHI/Include/RHI/CommandRecorder.h b/Engine/Source/RHI/Include/RHI/CommandRecorder.h index fcd40695d..ac747439d 100644 --- a/Engine/Source/RHI/Include/RHI/CommandRecorder.h +++ b/Engine/Source/RHI/Include/RHI/CommandRecorder.h @@ -180,13 +180,13 @@ namespace RHI { RasterPassBeginInfo& AddColorAttachment(const ColorAttachment& inColorAttachment); }; - class CommandCommandRecorder { + class CommonCommandRecorder { public: - virtual ~CommandCommandRecorder(); + virtual ~CommonCommandRecorder(); virtual void ResourceBarrier(const Barrier& barrier) = 0; }; - class CopyPassCommandRecorder : public CommandCommandRecorder { + class CopyPassCommandRecorder : public CommonCommandRecorder { public: NonCopyable(CopyPassCommandRecorder) ~CopyPassCommandRecorder() override; @@ -202,7 +202,7 @@ namespace RHI { CopyPassCommandRecorder(); }; - class ComputePassCommandRecorder : public CommandCommandRecorder { + class ComputePassCommandRecorder : public CommonCommandRecorder { public: NonCopyable(ComputePassCommandRecorder) ~ComputePassCommandRecorder() override; @@ -216,7 +216,7 @@ namespace RHI { ComputePassCommandRecorder(); }; - class RasterPassCommandRecorder : public CommandCommandRecorder { + class RasterPassCommandRecorder : public CommonCommandRecorder { public: NonCopyable(RasterPassCommandRecorder) ~RasterPassCommandRecorder() override; @@ -241,7 +241,7 @@ namespace RHI { RasterPassCommandRecorder(); }; - class CommandRecorder : public CommandCommandRecorder { + class CommandRecorder : public CommonCommandRecorder { public: NonCopyable(CommandRecorder) ~CommandRecorder() override; diff --git a/Engine/Source/RHI/Include/RHI/Common.h b/Engine/Source/RHI/Include/RHI/Common.h index 7c6f9824f..594174c0e 100644 --- a/Engine/Source/RHI/Include/RHI/Common.h +++ b/Engine/Source/RHI/Include/RHI/Common.h @@ -6,21 +6,44 @@ #include #include +#include #include #include #include #include -#define DECLARE_EC_FUNC() template inline B EnumCast(const A& value); -#define ECIMPL_BEGIN(A, B) template <> inline B EnumCast(const A& value) { -#define ECIMPL_ITEM(A, B) if (value == A) { return B; } -#define ECIMPL_END(B) Unimplement(); return (B) 0; }; - -#define DECLARE_FC_FUNC() template inline B FlagsCast(const A& flags); -#define FCIMPL_BEGIN(A, B) template <> inline B FlagsCast(const A& flags) { B result = (B) 0; -#define FCIMPL_ITEM(A, B) if (flags & A) { result |= B; } -#define FCIMPL_END(B) return result; }; +// EnumCast/FlagsCast model each backend's enum mapping as a static lookup table instead of an if-chain: a per-(A, B) +// EnumCastImpl/FlagsCastImpl specialization carries only the data, while the shared EnumCast/FlagsCast walk that data. +// Casting a pair that has no specialization fails to compile (the primary template has no member table), so a missing +// mapping is caught at build time rather than reaching Unimplement() at runtime. +#define DECLARE_EC_FUNC() \ + template struct EnumCastImpl {}; \ + template inline B EnumCast(const A& value) \ + { \ + for (const auto& pair : EnumCastImpl::table) { \ + if (pair.first == value) { return pair.second; } \ + } \ + Unimplement(); \ + return static_cast(0); \ + } +#define ECIMPL_BEGIN(A, B) template <> struct EnumCastImpl { static constexpr std::pair table[] = { +#define ECIMPL_ITEM(A, B) { A, B }, +#define ECIMPL_END(B) }; }; + +#define DECLARE_FC_FUNC() \ + template struct FlagsCastImpl {}; \ + template inline B FlagsCast(const A& flags) \ + { \ + B result = static_cast(0); \ + for (const auto& pair : FlagsCastImpl::table) { \ + if (flags & pair.first) { result |= pair.second; } \ + } \ + return result; \ + } +#define FCIMPL_BEGIN(A, B) template <> struct FlagsCastImpl { static inline const std::pair table[] = { +#define FCIMPL_ITEM(A, B) { A, B }, +#define FCIMPL_END(B) }; }; #define ALIGN_AS_GPU alignas(16) @@ -327,8 +350,8 @@ namespace RHI { enum class BlendOp : uint8_t { opAdd, - opSubstract, - opReverseSubstract, + opSubtract, + opReverseSubtract, opMin, opMax, max diff --git a/Engine/Source/RHI/Include/RHI/Pipeline.h b/Engine/Source/RHI/Include/RHI/Pipeline.h index 1e58a2b1c..ca946d9b8 100644 --- a/Engine/Source/RHI/Include/RHI/Pipeline.h +++ b/Engine/Source/RHI/Include/RHI/Pipeline.h @@ -108,7 +108,6 @@ namespace RHI { PrimitiveState& SetFrontFace(FrontFace inFrontFace); PrimitiveState& SetCullMode(CullMode inCullMode); PrimitiveState& SetDepthClip(bool inDepthClip); - uint64_t Hash() const; }; struct StencilFaceState { @@ -161,7 +160,6 @@ namespace RHI { DepthStencilState& SetDepthBias(int32_t inDepthBias); DepthStencilState& SetDepthBiasSlopeScale(float inDepthBiasSlopeScale); DepthStencilState& SetDepthBiasClamp(float inDepthBiasClamp); - uint64_t Hash() const; }; struct MultiSampleState { @@ -177,7 +175,6 @@ namespace RHI { MultiSampleState& SetCount(uint8_t inCount); MultiSampleState& SetMask(uint32_t inMask); MultiSampleState& SetAlphaToCoverage(bool inAlphaToCoverage); - uint64_t Hash() const; }; struct BlendComponent { @@ -210,7 +207,6 @@ namespace RHI { ColorTargetState& SetBlendEnabled(bool inBlendEnabled); ColorTargetState& SetColorBlend(const BlendComponent& inColorBlend); ColorTargetState& SetAlphaBlend(const BlendComponent& inAlphaBlend); - uint64_t Hash() const; }; struct FragmentState { @@ -218,7 +214,6 @@ namespace RHI { FragmentState(); FragmentState& AddColorTarget(const ColorTargetState& inState); - uint64_t Hash() const; }; struct ComputePipelineCreateInfo { diff --git a/Engine/Source/RHI/Include/RHI/Texture.h b/Engine/Source/RHI/Include/RHI/Texture.h index 2f3551d51..132a40623 100644 --- a/Engine/Source/RHI/Include/RHI/Texture.h +++ b/Engine/Source/RHI/Include/RHI/Texture.h @@ -37,8 +37,6 @@ namespace RHI { TextureCreateInfo& SetInitialState(TextureState inState); TextureCreateInfo& SetDebugName(std::string inDebugName); - uint64_t Hash() const; - bool operator==(const TextureCreateInfo& rhs) const; }; diff --git a/Engine/Source/RHI/Include/RHI/TextureView.h b/Engine/Source/RHI/Include/RHI/TextureView.h index b23a253fd..9044c4757 100644 --- a/Engine/Source/RHI/Include/RHI/TextureView.h +++ b/Engine/Source/RHI/Include/RHI/TextureView.h @@ -5,7 +5,6 @@ #pragma once #include -#include #include namespace RHI { @@ -32,8 +31,6 @@ namespace RHI { TextureViewCreateInfo& SetAspect(TextureAspect inAspect); TextureViewCreateInfo& SetMipLevels(uint8_t inBaseMipLevel, uint8_t inMipLevelNum); TextureViewCreateInfo& SetArrayLayers(uint8_t inBaseArrayLayer, uint8_t inArrayLayerNum); - - uint64_t Hash() const; }; class TextureView { diff --git a/Engine/Source/RHI/Src/Buffer.cpp b/Engine/Source/RHI/Src/Buffer.cpp index 88b493ad1..a1d9479d7 100644 --- a/Engine/Source/RHI/Src/Buffer.cpp +++ b/Engine/Source/RHI/Src/Buffer.cpp @@ -37,16 +37,6 @@ namespace RHI { return *this; } - uint64_t BufferCreateInfo::Hash() const - { - const std::vector values = { - size, - static_cast(usages.Value()), - static_cast(initialState), - }; - return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); - } - bool BufferCreateInfo::operator==(const BufferCreateInfo& rhs) const { return size == rhs.size diff --git a/Engine/Source/RHI/Src/BufferView.cpp b/Engine/Source/RHI/Src/BufferView.cpp index 6402f76c2..ce040c7b7 100644 --- a/Engine/Source/RHI/Src/BufferView.cpp +++ b/Engine/Source/RHI/Src/BufferView.cpp @@ -68,11 +68,6 @@ namespace RHI { return *this; } - uint64_t BufferViewCreateInfo::Hash() const - { - return Common::HashUtils::CityHash(this, sizeof(BufferViewCreateInfo)); - } - BufferView::BufferView(const BufferViewCreateInfo&) {} BufferView::~BufferView() = default; diff --git a/Engine/Source/RHI/Src/CommandRecorder.cpp b/Engine/Source/RHI/Src/CommandRecorder.cpp index b1bea46b6..d553f51b6 100644 --- a/Engine/Source/RHI/Src/CommandRecorder.cpp +++ b/Engine/Source/RHI/Src/CommandRecorder.cpp @@ -194,7 +194,7 @@ namespace RHI { CommandRecorder::~CommandRecorder() = default; - CommandCommandRecorder::~CommandCommandRecorder() = default; + CommonCommandRecorder::~CommonCommandRecorder() = default; CopyPassCommandRecorder::CopyPassCommandRecorder() = default; diff --git a/Engine/Source/RHI/Src/Common.cpp b/Engine/Source/RHI/Src/Common.cpp index 48887d3e6..0016c3f3a 100644 --- a/Engine/Source/RHI/Src/Common.cpp +++ b/Engine/Source/RHI/Src/Common.cpp @@ -7,20 +7,23 @@ namespace RHI { size_t GetBytesPerPixel(PixelFormat format) { - if (format > PixelFormat::begin8Bits && format < PixelFormat::begin16Bits) { - return 1; - } - if (format > PixelFormat::begin16Bits && format < PixelFormat::begin32Bits) { - return 2; - } - if (format > PixelFormat::begin32Bits && format < PixelFormat::begin64Bits) { - return 4; - } - if (format > PixelFormat::begin64Bits && format < PixelFormat::begin128Bits) { - return 8; - } - if (format > PixelFormat::begin128Bits && format < PixelFormat::max) { - return 16; + struct BytesPerPixelRange { + PixelFormat begin; + PixelFormat end; + size_t bytesPerPixel; + }; + static constexpr BytesPerPixelRange ranges[] = { + { PixelFormat::begin8Bits, PixelFormat::begin16Bits, 1 }, + { PixelFormat::begin16Bits, PixelFormat::begin32Bits, 2 }, + { PixelFormat::begin32Bits, PixelFormat::begin64Bits, 4 }, + { PixelFormat::begin64Bits, PixelFormat::begin128Bits, 8 }, + { PixelFormat::begin128Bits, PixelFormat::max, 16 }, + }; + + for (const auto& range : ranges) { + if (format > range.begin && format < range.end) { + return range.bytesPerPixel; + } } return Assert(false), 1; } diff --git a/Engine/Source/RHI/Src/Pipeline.cpp b/Engine/Source/RHI/Src/Pipeline.cpp index 399bbd4ab..e5e09a16d 100644 --- a/Engine/Source/RHI/Src/Pipeline.cpp +++ b/Engine/Source/RHI/Src/Pipeline.cpp @@ -3,7 +3,6 @@ // #include -#include namespace RHI { HlslVertexBinding::HlslVertexBinding() @@ -112,11 +111,6 @@ namespace RHI { return *this; } - uint64_t PrimitiveState::Hash() const - { - return Common::HashUtils::CityHash(this, sizeof(PrimitiveState)); - } - StencilFaceState::StencilFaceState( const CompareFunc inCompareFunc, const StencilOp inFailOp, @@ -221,11 +215,6 @@ namespace RHI { return *this; } - uint64_t DepthStencilState::Hash() const - { - return Common::HashUtils::CityHash(this, sizeof(DepthStencilState)); - } - MultiSampleState::MultiSampleState(const uint8_t inCount, const uint32_t inMask, const bool inAlphaToCoverage) : count(inCount) , mask(inMask) @@ -251,11 +240,6 @@ namespace RHI { return *this; } - uint64_t MultiSampleState::Hash() const - { - return Common::HashUtils::CityHash(this, sizeof(MultiSampleState)); - } - BlendComponent::BlendComponent(const BlendOp inOp, const BlendFactor inSrcFactor, const BlendFactor inDstFactor) : op(inOp) , srcFactor(inSrcFactor) @@ -307,11 +291,6 @@ namespace RHI { return *this; } - uint64_t ColorTargetState::Hash() const - { - return Common::HashUtils::CityHash(this, sizeof(ColorTargetState)); - } - FragmentState::FragmentState() { } @@ -322,17 +301,6 @@ namespace RHI { return *this; } - uint64_t FragmentState::Hash() const - { - std::vector values; - values.reserve(colorTargets.size()); - - for (const auto& colorTarget : colorTargets) { - values.emplace_back(colorTarget.Hash()); - } - return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); - } - ComputePipelineCreateInfo::ComputePipelineCreateInfo() : layout(nullptr) , computeShader(nullptr) diff --git a/Engine/Source/RHI/Src/Texture.cpp b/Engine/Source/RHI/Src/Texture.cpp index e9674a6b9..0464678d8 100644 --- a/Engine/Source/RHI/Src/Texture.cpp +++ b/Engine/Source/RHI/Src/Texture.cpp @@ -78,22 +78,6 @@ namespace RHI { return *this; } - uint64_t TextureCreateInfo::Hash() const - { - const std::vector values = { - static_cast(dimension), - static_cast(width), - static_cast(height), - static_cast(depthOrArraySize), - static_cast(format), - static_cast(usages.Value()), - static_cast(mipLevels), - static_cast(samples), - static_cast(initialState), - }; - return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); - } - bool TextureCreateInfo::operator==(const TextureCreateInfo& rhs) const { return dimension == rhs.dimension diff --git a/Engine/Source/RHI/Src/TextureView.cpp b/Engine/Source/RHI/Src/TextureView.cpp index afb0423ad..0221a67ec 100644 --- a/Engine/Source/RHI/Src/TextureView.cpp +++ b/Engine/Source/RHI/Src/TextureView.cpp @@ -55,11 +55,6 @@ namespace RHI { return *this; } - uint64_t TextureViewCreateInfo::Hash() const - { - return Common::HashUtils::CityHash(this, sizeof(TextureViewCreateInfo)); - } - TextureView::TextureView(const TextureViewCreateInfo&) {} TextureView::~TextureView() = default; diff --git a/Engine/Source/Render/Include/Render/RenderGraph.h b/Engine/Source/Render/Include/Render/RenderGraph.h index 0288b8bbb..7a799ace8 100644 --- a/Engine/Source/Render/Include/Render/RenderGraph.h +++ b/Engine/Source/Render/Include/Render/RenderGraph.h @@ -399,11 +399,11 @@ namespace Render { void DevirtualizeAttachmentViews(const RGRasterPassDesc& inDesc); void FinalizePassResources(const std::unordered_set& inResources); void FinalizePassBindGroups(const std::vector& inBindGroups); - void TransitionResourcesForCopyPassDesc(RHI::CommandCommandRecorder& inRecoder, const RGCopyPassDesc& inDesc); - void TransitionResourcesForRasterPassDesc(RHI::CommandCommandRecorder& inRecoder, const RGRasterPassDesc& inDesc); - void TransitionResourcesForBindGroups(RHI::CommandCommandRecorder& inRecoder, const std::vector& inBindGroups); - void TransitionBuffer(RHI::CommandCommandRecorder& inRecoder, RGBufferRef inBuffer, RHI::BufferState inState); - void TransitionTexture(RHI::CommandCommandRecorder& inRecoder, RGTextureRef inTexture, RHI::TextureState inState); + void TransitionResourcesForCopyPassDesc(RHI::CommonCommandRecorder& inRecoder, const RGCopyPassDesc& inDesc); + void TransitionResourcesForRasterPassDesc(RHI::CommonCommandRecorder& inRecoder, const RGRasterPassDesc& inDesc); + void TransitionResourcesForBindGroups(RHI::CommonCommandRecorder& inRecoder, const std::vector& inBindGroups); + void TransitionBuffer(RHI::CommonCommandRecorder& inRecoder, RGBufferRef inBuffer, RHI::BufferState inState); + void TransitionTexture(RHI::CommonCommandRecorder& inRecoder, RGTextureRef inTexture, RHI::TextureState inState); bool executed; RHI::Device& device; diff --git a/Engine/Source/Render/Src/RenderCache.cpp b/Engine/Source/Render/Src/RenderCache.cpp index 5fb8c7a23..14e26aa9e 100644 --- a/Engine/Source/Render/Src/RenderCache.cpp +++ b/Engine/Source/Render/Src/RenderCache.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -12,6 +13,84 @@ namespace Render::Internal { constexpr uint64_t resourceViewCacheReleaseFrameLatency = 2; constexpr uint64_t bindGroupCacheReleaseFrameLatency = 2; + + static uint64_t CombineHashes(const std::vector& hashes) + { + return Common::HashUtils::CityHash(hashes.data(), hashes.size() * sizeof(uint64_t)); + } + + template + static uint64_t HashRhiState(const T& value) + { + return Common::HashUtils::CityHash(&value, sizeof(T)); + } + + static uint64_t HashRhiState(const RHI::MultiSampleState& state) + { + return CombineHashes({ + static_cast(state.count), + static_cast(state.mask), + static_cast(state.alphaToCoverage) + }); + } + + static uint64_t HashRhiState(const RHI::DepthStencilState& state) + { + return CombineHashes({ + static_cast(state.depthEnabled), + static_cast(state.stencilEnabled), + static_cast(state.format), + static_cast(state.depthCompareFunc), + static_cast(static_cast(state.depthBias)), + HashRhiState(state.depthBiasSlopeScale), + HashRhiState(state.depthBiasClamp), + HashRhiState(state.stencilFront), + HashRhiState(state.stencilBack), + static_cast(state.stencilReadMask), + static_cast(state.stencilWriteMask) + }); + } + + static uint64_t HashRhiState(const RHI::BufferViewCreateInfo& createInfo) + { + const uint64_t extendHash = std::visit( + [](const auto& alternative) -> uint64_t { return HashRhiState(alternative); }, + createInfo.extend); + return CombineHashes({ + static_cast(createInfo.type), + static_cast(createInfo.size), + static_cast(createInfo.offset), + static_cast(createInfo.extend.index()), + extendHash + }); + } + + static uint64_t HashRhiState(const RHI::SamplerCreateInfo& createInfo) + { + return CombineHashes({ + static_cast(createInfo.addressModeU), + static_cast(createInfo.addressModeV), + static_cast(createInfo.addressModeW), + static_cast(createInfo.magFilter), + static_cast(createInfo.minFilter), + static_cast(createInfo.mipFilter), + HashRhiState(createInfo.lodMinClamp), + HashRhiState(createInfo.lodMaxClamp), + static_cast(createInfo.comparisonFunc), + static_cast(createInfo.maxAnisotropy) + }); + } + + // FragmentState owns a vector of color targets, so it cannot be hashed as a flat blob like the other states. + static uint64_t HashRhiState(const RHI::FragmentState& fragmentState) + { + std::vector values; + values.reserve(fragmentState.colorTargets.size()); + for (const auto& colorTarget : fragmentState.colorTargets) { + values.emplace_back(HashRhiState(colorTarget)); + } + return CombineHashes(values); + } } namespace Render { @@ -287,10 +366,10 @@ namespace Render { const std::vector values = { shaders.Hash(), vertexState.Hash(), - primitiveState.Hash(), - depthStencilState.Hash(), - multiSampleState.Hash(), - fragmentState.Hash() + Internal::HashRhiState(primitiveState), + Internal::HashRhiState(depthStencilState), + Internal::HashRhiState(multiSampleState), + Internal::HashRhiState(fragmentState) }; return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); } @@ -534,7 +613,7 @@ namespace Render { Sampler* SamplerCache::GetOrCreate(const RSamplerDesc& desc) { - const size_t hash = Common::HashUtils::CityHash(&desc, sizeof(RSamplerDesc)); + const size_t hash = Internal::HashRhiState(desc); if (const auto iter = samplers.find(hash); iter == samplers.end()) { samplers[hash] = Common::UniquePtr(new Sampler(device, desc)); @@ -614,7 +693,7 @@ namespace Render { { auto& views = bufferViewCaches[buffer].views; - auto hash = inDesc.Hash(); + auto hash = Internal::HashRhiState(inDesc); if (const auto iter = views.find(hash); iter == views.end()) { views.emplace(std::make_pair(hash, Common::UniquePtr(buffer->CreateBufferView(inDesc)))); @@ -626,7 +705,7 @@ namespace Render { { auto& views = textureViewCaches[texture].views; - auto hash = inDesc.Hash(); + auto hash = Internal::HashRhiState(inDesc); if (const auto iter = views.find(hash); iter == views.end()) { views.emplace(std::make_pair(hash, Common::UniquePtr(texture->CreateTextureView(inDesc)))); diff --git a/Engine/Source/Render/Src/RenderGraph.cpp b/Engine/Source/Render/Src/RenderGraph.cpp index 15db55fa4..c119bac86 100644 --- a/Engine/Source/Render/Src/RenderGraph.cpp +++ b/Engine/Source/Render/Src/RenderGraph.cpp @@ -873,7 +873,7 @@ namespace Render { const auto* src = srcDataPtr + uploadInfo.srcOffset; // NOLINT auto* dst = rhiBuffer->Map(RHI::MapMode::write, uploadInfo.dstOffset, srcDataSize); memcpy(dst, src, srcDataSize); - rhiBuffer->UnMap(); + rhiBuffer->Unmap(); })); } } @@ -1003,7 +1003,7 @@ namespace Render { } } - void RGBuilder::TransitionResourcesForCopyPassDesc(RHI::CommandCommandRecorder& inRecoder, const RGCopyPassDesc& inDesc) + void RGBuilder::TransitionResourcesForCopyPassDesc(RHI::CommonCommandRecorder& inRecoder, const RGCopyPassDesc& inDesc) { for (auto* copySrc : inDesc.copySrcs) { if (copySrc->type == RGResType::buffer) { @@ -1025,7 +1025,7 @@ namespace Render { } } - void RGBuilder::TransitionResourcesForRasterPassDesc(RHI::CommandCommandRecorder& inRecoder, const RGRasterPassDesc& inDesc) + void RGBuilder::TransitionResourcesForRasterPassDesc(RHI::CommonCommandRecorder& inRecoder, const RGRasterPassDesc& inDesc) { if (inDesc.depthStencilAttachment.has_value()) { const auto& dsa = inDesc.depthStencilAttachment.value(); @@ -1036,7 +1036,7 @@ namespace Render { } } - void RGBuilder::TransitionResourcesForBindGroups(RHI::CommandCommandRecorder& inRecoder, const std::vector& inBindGroups) + void RGBuilder::TransitionResourcesForBindGroups(RHI::CommonCommandRecorder& inRecoder, const std::vector& inBindGroups) { for (auto* bindGroup : inBindGroups) { for (const auto& [type, view] : bindGroup->desc.items | std::views::values) { @@ -1057,7 +1057,7 @@ namespace Render { } } - void RGBuilder::TransitionBuffer(RHI::CommandCommandRecorder& inRecoder, RGBufferRef inBuffer, RHI::BufferState inState) + void RGBuilder::TransitionBuffer(RHI::CommonCommandRecorder& inRecoder, RGBufferRef inBuffer, RHI::BufferState inState) { auto& currentState = std::get(resourceStates.at(inBuffer)); if (currentState == inState) { @@ -1067,7 +1067,7 @@ namespace Render { currentState = inState; } - void RGBuilder::TransitionTexture(RHI::CommandCommandRecorder& inRecoder, RGTextureRef inTexture, RHI::TextureState inState) + void RGBuilder::TransitionTexture(RHI::CommonCommandRecorder& inRecoder, RGTextureRef inTexture, RHI::TextureState inState) { auto& currentState = std::get(resourceStates.at(inTexture)); if (currentState == inState) { diff --git a/Engine/Source/Runtime/Src/Asset/Texture.cpp b/Engine/Source/Runtime/Src/Asset/Texture.cpp index babd29083..d3cd71522 100644 --- a/Engine/Source/Runtime/Src/Asset/Texture.cpp +++ b/Engine/Source/Runtime/Src/Asset/Texture.cpp @@ -282,7 +282,7 @@ namespace Runtime { dstSubResourceOffset += dstCopyFootprint.totalBytes; } } - stagingBuffer->UnMap(); + stagingBuffer->Unmap(); const Common::UniquePtr cmdBuffer = device->CreateCommandBuffer(); const auto recoder = cmdBuffer->Begin(); diff --git a/Sample/RHI-ParallelCompute/ParallelCompute.cpp b/Sample/RHI-ParallelCompute/ParallelCompute.cpp index 8af4ff121..9c50476bf 100644 --- a/Sample/RHI-ParallelCompute/ParallelCompute.cpp +++ b/Sample/RHI-ParallelCompute/ParallelCompute.cpp @@ -43,7 +43,7 @@ class ParallelCompute final : public Application { << ")" << '\n'; } - readbackBuffer->UnMap(); + readbackBuffer->Unmap(); } private: void SelectGPU() @@ -75,7 +75,7 @@ class ParallelCompute final : public Application { if (stagingBuf != nullptr) { auto* mapPointer = stagingBuf->Map(MapMode::write, 0, bufInfo.size); memcpy(mapPointer, data.data(), bufInfo.size); - stagingBuf->UnMap(); + stagingBuf->Unmap(); } const auto inputBufInfo = BufferCreateInfo() diff --git a/Sample/RHI-SSAO/SSAOApplication.cpp b/Sample/RHI-SSAO/SSAOApplication.cpp index c8b0f64de..6f6656313 100644 --- a/Sample/RHI-SSAO/SSAOApplication.cpp +++ b/Sample/RHI-SSAO/SSAOApplication.cpp @@ -47,7 +47,7 @@ class SSAOApplication final : public Application { auto* pMap = uniformBuffers.sceneParams.buf->Map(MapMode::write, 0, sizeof(UBOSceneParams)); memcpy(pMap, &uboSceneParams, sizeof(UBOSceneParams)); - uniformBuffers.sceneParams.buf->UnMap(); + uniformBuffers.sceneParams.buf->Unmap(); inflightFences[nextFrameIndex]->Wait(); const auto backTextureIndex = swapChain->AcquireBackTexture(backBufferReadySemaphores[nextFrameIndex].Get()); @@ -252,7 +252,7 @@ class SSAOApplication final : public Application { auto* dst = static_cast(data) + i * copyFootprint.rowPitch; memcpy(dst, src, srcRowPitch); } - pixelBuffer->UnMap(); + pixelBuffer->Unmap(); } const UniquePtr texCommandBuffer = device.CreateCommandBuffer(); @@ -455,7 +455,7 @@ class SSAOApplication final : public Application { Assert(vertexBuffer != nullptr); auto* data = vertexBuffer->Map(MapMode::write, 0, bufferCreateInfo.size); memcpy(data, model->rawVertBuffer.data(), bufferCreateInfo.size); - vertexBuffer->UnMap(); + vertexBuffer->Unmap(); const BufferViewCreateInfo bufferViewCreateInfo = BufferViewCreateInfo() .SetType(BufferViewType::vertex) @@ -476,7 +476,7 @@ class SSAOApplication final : public Application { Assert(indexBuffer != nullptr); auto* data = indexBuffer->Map(MapMode::write, 0, bufferCreateInfo.size); memcpy(data, model->rawIndBuffer.data(), bufferCreateInfo.size); - indexBuffer->UnMap(); + indexBuffer->Unmap(); const BufferViewCreateInfo bufferViewCreateInfo = BufferViewCreateInfo() .SetType(BufferViewType::index) @@ -505,7 +505,7 @@ class SSAOApplication final : public Application { if (quadVertexBuffer != nullptr) { auto* data = quadVertexBuffer->Map(MapMode::write, 0, bufferCreateInfo.size); memcpy(data, vertices.data(), bufferCreateInfo.size); - quadVertexBuffer->UnMap(); + quadVertexBuffer->Unmap(); } BufferViewCreateInfo bufferViewCreateInfo = BufferViewCreateInfo() @@ -526,7 +526,7 @@ class SSAOApplication final : public Application { if (quadIndexBuffer != nullptr) { auto* data = quadIndexBuffer->Map(MapMode::write, 0, bufferCreateInfo.size); memcpy(data, indices.data(), bufferCreateInfo.size); - quadIndexBuffer->UnMap(); + quadIndexBuffer->Unmap(); } bufferViewCreateInfo = BufferViewCreateInfo() @@ -762,7 +762,7 @@ class SSAOApplication final : public Application { if (pixelBuffer != nullptr) { auto* data = pixelBuffer->Map(MapMode::write, 0, bufferCreateInfo.size); memcpy(data, ssaoNoise.data(), bufferCreateInfo.size); - pixelBuffer->UnMap(); + pixelBuffer->Unmap(); } noise.tex = device->CreateTexture( @@ -885,7 +885,7 @@ class SSAOApplication final : public Application { if (uBuffer->buf != nullptr && data != nullptr) { auto* mapData = uBuffer->buf->Map(MapMode::write, 0, size); memcpy(mapData, data, size); - uBuffer->buf->UnMap(); + uBuffer->buf->Unmap(); } const BufferViewCreateInfo viewCreateInfo = BufferViewCreateInfo() diff --git a/Sample/RHI-TexSampling/TexSampling.cpp b/Sample/RHI-TexSampling/TexSampling.cpp index 986c4402c..96f50ef7b 100644 --- a/Sample/RHI-TexSampling/TexSampling.cpp +++ b/Sample/RHI-TexSampling/TexSampling.cpp @@ -162,7 +162,7 @@ class TexSamplingApplication final : public Application { if (vertexBuffer != nullptr) { auto* data = vertexBuffer->Map(MapMode::write, 0, bufferCreateInfo.size); memcpy(data, vertices.data(), bufferCreateInfo.size); - vertexBuffer->UnMap(); + vertexBuffer->Unmap(); } const BufferViewCreateInfo bufferViewCreateInfo = BufferViewCreateInfo() @@ -187,7 +187,7 @@ class TexSamplingApplication final : public Application { if (indexBuffer != nullptr) { auto* data = indexBuffer->Map(MapMode::write, 0, bufferCreateInfo.size); memcpy(data, indices.data(), bufferCreateInfo.size); - indexBuffer->UnMap(); + indexBuffer->Unmap(); } const BufferViewCreateInfo bufferViewCreateInfo = BufferViewCreateInfo() @@ -241,7 +241,7 @@ class TexSamplingApplication final : public Application { auto* dst = static_cast(data) + i * copyFootprint.rowPitch; memcpy(dst, src, srcRowPitch); } - pixelBuffer->UnMap(); + pixelBuffer->Unmap(); } stbi_image_free(pixels); @@ -278,7 +278,7 @@ class TexSamplingApplication final : public Application { if (uniformBuffer != nullptr) { auto* mapData = uniformBuffer->Map(MapMode::write, 0, sizeof(FMat4x4)); memcpy(mapData, &modelMatrix, sizeof(FMat4x4)); - uniformBuffer->UnMap(); + uniformBuffer->Unmap(); } } diff --git a/Sample/RHI-Triangle/Triangle.cpp b/Sample/RHI-Triangle/Triangle.cpp index a9619100c..221d3f80c 100644 --- a/Sample/RHI-Triangle/Triangle.cpp +++ b/Sample/RHI-Triangle/Triangle.cpp @@ -152,7 +152,7 @@ class TriangleApplication final : public Application { if (vertexBuffer != nullptr) { auto* data = vertexBuffer->Map(MapMode::write, 0, bufferCreateInfo.size); memcpy(data, vertices.data(), bufferCreateInfo.size); - vertexBuffer->UnMap(); + vertexBuffer->Unmap(); } const BufferViewCreateInfo bufferViewCreateInfo = BufferViewCreateInfo() diff --git a/Sample/Rendering-BaseTexture/BaseTexture.cpp b/Sample/Rendering-BaseTexture/BaseTexture.cpp index 6824aeb68..931d757d6 100644 --- a/Sample/Rendering-BaseTexture/BaseTexture.cpp +++ b/Sample/Rendering-BaseTexture/BaseTexture.cpp @@ -304,7 +304,7 @@ void BaseTexApp::CreateVertexAndIndexBuffer() if (vertexBuffer != nullptr) { auto* data = vertexBuffer->Map(MapMode::write, 0, bufferCreateInfo.size); memcpy(data, vertices.data(), bufferCreateInfo.size); - vertexBuffer->UnMap(); + vertexBuffer->Unmap(); } const std::vector indices = {0, 1, 2, 0, 2, 3}; @@ -318,7 +318,7 @@ void BaseTexApp::CreateVertexAndIndexBuffer() if (indexBuffer != nullptr) { auto* data = indexBuffer->Map(MapMode::write, 0, indexInfo.size); memcpy(data, indices.data(), bufferCreateInfo.size); - indexBuffer->UnMap(); + indexBuffer->Unmap(); } } @@ -358,7 +358,7 @@ void BaseTexApp::CreateTextureAndSampler() auto* dst = static_cast(data) + i * copyFootprint.rowPitch; memcpy(dst, src, srcRowPitch); } - imageBuffer->UnMap(); + imageBuffer->Unmap(); } stbi_image_free(imgData); diff --git a/Sample/Rendering-SSAO/SSAOApplication.cpp b/Sample/Rendering-SSAO/SSAOApplication.cpp index 83fce3b78..d7a9b9a36 100644 --- a/Sample/Rendering-SSAO/SSAOApplication.cpp +++ b/Sample/Rendering-SSAO/SSAOApplication.cpp @@ -172,7 +172,7 @@ class SSAOApp final : public Application { if (uniformBuffers.sceneParams) { auto* uboData = uniformBuffers.sceneParams->Map(MapMode::write, 0, sizeof(UBOSceneParams)); memcpy(uboData, &uboSceneParams, sizeof(UBOSceneParams)); - uniformBuffers.sceneParams->UnMap(); + uniformBuffers.sceneParams->Unmap(); } RGBuilder builder(*device); @@ -606,7 +606,7 @@ class SSAOApp final : public Application { if (vertexBuffer != nullptr) { auto* data = vertexBuffer->Map(MapMode::write, 0, vBufferInfo.size); memcpy(data, model->rawVertBuffer.data(), vBufferInfo.size); - vertexBuffer->UnMap(); + vertexBuffer->Unmap(); } // Index buffer @@ -620,7 +620,7 @@ class SSAOApp final : public Application { if (indexBuffer != nullptr) { auto* data = indexBuffer->Map(MapMode::write, 0, iBufferInfo.size); memcpy(data, model->rawIndBuffer.data(), iBufferInfo.size); - indexBuffer->UnMap(); + indexBuffer->Unmap(); } } @@ -644,7 +644,7 @@ class SSAOApp final : public Application { if (quadVertexBuffer != nullptr) { auto* data = quadVertexBuffer->Map(MapMode::write, 0, vBufferInfo.size); memcpy(data, vertices.data(), vBufferInfo.size); - quadVertexBuffer->UnMap(); + quadVertexBuffer->Unmap(); } // Quad index buffer @@ -659,7 +659,7 @@ class SSAOApp final : public Application { if (quadIndexBuffer != nullptr) { auto* data = quadIndexBuffer->Map(MapMode::write, 0, iBufferInfo.size); memcpy(data, indices.data(), iBufferInfo.size); - quadIndexBuffer->UnMap(); + quadIndexBuffer->Unmap(); } } @@ -787,7 +787,7 @@ class SSAOApp final : public Application { if (uniformBuffers.sceneParams != nullptr) { auto* data = uniformBuffers.sceneParams->Map(MapMode::write, 0, sizeof(UBOSceneParams)); memcpy(data, &uboSceneParams, sizeof(UBOSceneParams)); - uniformBuffers.sceneParams->UnMap(); + uniformBuffers.sceneParams->Unmap(); } // SSAO parameters @@ -803,7 +803,7 @@ class SSAOApp final : public Application { if (uniformBuffers.ssaoParams != nullptr) { auto* data = uniformBuffers.ssaoParams->Map(MapMode::write, 0, sizeof(UBOSSAOParams)); memcpy(data, &ubossaoParams, sizeof(UBOSSAOParams)); - uniformBuffers.ssaoParams->UnMap(); + uniformBuffers.ssaoParams->Unmap(); } // SSAO kernel @@ -835,7 +835,7 @@ class SSAOApp final : public Application { if (uniformBuffers.ssaoKernel != nullptr) { auto* data = uniformBuffers.ssaoKernel->Map(MapMode::write, 0, kernelInfo.size); memcpy(data, ssaoKernel.data(), kernelInfo.size); - uniformBuffers.ssaoKernel->UnMap(); + uniformBuffers.ssaoKernel->Unmap(); } } @@ -859,7 +859,7 @@ class SSAOApp final : public Application { if (stagingBuffer != nullptr) { auto* data = stagingBuffer->Map(MapMode::write, 0, bufferInfo.size); memcpy(data, ssaoNoise.data(), bufferInfo.size); - stagingBuffer->UnMap(); + stagingBuffer->Unmap(); } noiseTex = device->CreateTexture( @@ -936,7 +936,7 @@ class SSAOApp final : public Application { auto* dst = static_cast(data) + i * copyFootprint.rowPitch; memcpy(dst, src, srcRowPitch); } - stagingBuffer->UnMap(); + stagingBuffer->Unmap(); } auto copyCmdBuffer = device->CreateCommandBuffer(); diff --git a/Sample/Rendering-Triangle/Triangle.cpp b/Sample/Rendering-Triangle/Triangle.cpp index 9baa375a1..a67f87206 100644 --- a/Sample/Rendering-Triangle/Triangle.cpp +++ b/Sample/Rendering-Triangle/Triangle.cpp @@ -286,7 +286,7 @@ void TriangleApplication::CreateTriangleVertexBuffer() if (triangleVertexBuffer != nullptr) { auto* data = triangleVertexBuffer->Map(MapMode::write, 0, bufferCreateInfo.size); memcpy(data, vertices.data(), bufferCreateInfo.size); - triangleVertexBuffer->UnMap(); + triangleVertexBuffer->Unmap(); } } diff --git a/ThirdParty/Registry.cmake b/ThirdParty/Registry.cmake index 53e007e39..ef8e2a813 100644 --- a/ThirdParty/Registry.cmake +++ b/ThirdParty/Registry.cmake @@ -10,6 +10,15 @@ else () endif () find_package(httplib REQUIRED GLOBAL) + +# glfw requires opengl/system only to propagate headers and the OpenGL framework (libs=False, it never links GL). On +# Apple that package carries just cpp_info.frameworks, which the new CMakeConfigDeps generator forgets to count when +# deciding whether to emit a target, so opengl::opengl is never created and glfw's link interface dangles. Recreate it. +if (APPLE AND NOT TARGET opengl::opengl) + add_library(opengl::opengl INTERFACE IMPORTED GLOBAL) + target_link_libraries(opengl::opengl INTERFACE "-framework OpenGL") +endif () + find_package(glfw3 REQUIRED GLOBAL) find_package(stb REQUIRED GLOBAL) find_package(cityhash REQUIRED GLOBAL)