From 360154e88a0a0da9c6e86a36c48ebc6b08126c74 Mon Sep 17 00:00:00 2001 From: Danilo Date: Fri, 8 Nov 2024 11:13:44 -0300 Subject: [PATCH] =?UTF-8?q?Implementa=C3=A7=C3=B5es=20iniciais=20do=20pipe?= =?UTF-8?q?line?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- includes/pipeline/compiler.hpp | 45 +++++ includes/pipeline/default.hpp | 14 ++ includes/pipeline/discard.hpp | 0 includes/pipeline/enums.hpp | 11 ++ includes/pipeline/pipeline.hpp | 10 ++ includes/pipeline/writer.hpp | 286 ++++++++++++++++++++++++++++++++ includes/xna/default.hpp | 15 +- sources/pipeline/CMakeLists.txt | 5 +- sources/pipeline/compiler.cpp | 38 +++++ sources/pipeline/discard.cpp | 0 sources/pipeline/writer.cpp | 171 +++++++++++++++++++ 11 files changed, 588 insertions(+), 7 deletions(-) create mode 100644 includes/pipeline/compiler.hpp create mode 100644 includes/pipeline/default.hpp delete mode 100644 includes/pipeline/discard.hpp create mode 100644 includes/pipeline/enums.hpp create mode 100644 includes/pipeline/pipeline.hpp create mode 100644 includes/pipeline/writer.hpp create mode 100644 sources/pipeline/compiler.cpp delete mode 100644 sources/pipeline/discard.cpp create mode 100644 sources/pipeline/writer.cpp diff --git a/includes/pipeline/compiler.hpp b/includes/pipeline/compiler.hpp new file mode 100644 index 0000000..ff9a7de --- /dev/null +++ b/includes/pipeline/compiler.hpp @@ -0,0 +1,45 @@ +#ifndef XNA_PIPELINE_COMPILER_HPP +#define XNA_PIPELINE_COMPILER_HPP + +#include "xna/default.hpp" +#include "xna/csharp/stream.hpp" +#include "pipeline-enums.hpp" +#include "default.hpp" +#include + +namespace xna { + //Provides methods for writing compiled binary format. + class ContentCompiler : public std::enable_shared_from_this { + public: + ContentCompiler(); + + //Retrieves the worker writer for the specified type + P_ContentTypeWriter GetTypeWriter(Type const& type, std::vector dependencies); + + private: + void Compile( + P_Stream const& output, + Object& value, + TargetPlatform targetPlatform, + GraphicsProfile targetProfile, + bool compressContent, + String const& rootDirectory, + String const& referenceRelocationPath); + + void AddTypeWriter(P_ContentTypeWriter const& writer); + + bool ShouldCompressContent(TargetPlatform targetPlatform, Object& value) { + return false; + } + + private: + using TypeList = std::vector; + + std::map writerInstances; + std::map writerDependecies; + std::stack initializeContext; + P_ContentTypeWriterFactory typeWriterFactory; + }; +} + +#endif \ No newline at end of file diff --git a/includes/pipeline/default.hpp b/includes/pipeline/default.hpp new file mode 100644 index 0000000..0d8236b --- /dev/null +++ b/includes/pipeline/default.hpp @@ -0,0 +1,14 @@ +#ifndef XNA_PIPELINE_DEFAULT_HPP +#define XNA_PIPELINE_DEFAULT_HPP + +#include "xna/default.hpp" + +namespace xna { + class ContentTypeWriter; + class ContentTypeWriterFactory; + + using P_ContentTypeWriter = sptr; + using P_ContentTypeWriterFactory = sptr; +} + +#endif \ No newline at end of file diff --git a/includes/pipeline/discard.hpp b/includes/pipeline/discard.hpp deleted file mode 100644 index e69de29..0000000 diff --git a/includes/pipeline/enums.hpp b/includes/pipeline/enums.hpp new file mode 100644 index 0000000..205ff0d --- /dev/null +++ b/includes/pipeline/enums.hpp @@ -0,0 +1,11 @@ +#ifndef XNA_PIPELINE_ENUMS_HPP +#define XNA_PIPELINE_ENUMS_HPP + +namespace xna { + enum class TargetPlatform + { + Windows, + }; +} + +#endif \ No newline at end of file diff --git a/includes/pipeline/pipeline.hpp b/includes/pipeline/pipeline.hpp new file mode 100644 index 0000000..d7c8b42 --- /dev/null +++ b/includes/pipeline/pipeline.hpp @@ -0,0 +1,10 @@ +#ifndef XNA_PIPELINE_PIPELINE_HPP +#define XNA_PIPELINE_PIPELINE_HPP + +namespace xna { + class Pipeline { + + }; +} + +#endif \ No newline at end of file diff --git a/includes/pipeline/writer.hpp b/includes/pipeline/writer.hpp new file mode 100644 index 0000000..d297375 --- /dev/null +++ b/includes/pipeline/writer.hpp @@ -0,0 +1,286 @@ +#ifndef XNA_PIPELINE_WRITER_HPP +#define XNA_PIPELINE_WRITER_HPP + +#include "xna/common/color.hpp" +#include "xna/common/numerics.hpp" +#include "xna/csharp/binary.hpp" +#include "xna/csharp/type.hpp" +#include "xna/default.hpp" +#include "default.hpp" +#include "enums.hpp" +#include + +namespace xna { + //Provides an implementation for many of the ContentCompiler methods including compilation, state tracking for shared resources and creation of the header type manifest. + class ContentTypeWriter { + public: + //Gets the assembly qualified name of the runtime loader for this type. + virtual String GetRuntimeReader(TargetPlatform targetPlatform) { return String(); } + //Gets a format version number for this type. + virtual Int TypeVersion() const { return 0; } + //Compiles an object into binary format. + virtual void Write(ContentWriter& output, Object& value) {} + //Determines if deserialization into an existing object is possible. + virtual bool CanDeserializeIntoExistingObject() const { return false; } + + protected: + ContentTypeWriter(P_Type const& targetType) : targetType(targetType) {} + + private: + P_Type targetType{ nullptr }; + }; + + //Provides a generic implementation of ContentTypeWriter methods and properties for compiling a specific managed type into a binary format. + template + class ContentTypeWriter_T : public ContentTypeWriter { + public: + //Compiles a strongly typed object into binary format. + virtual void Write(ContentWriter& output, T& value) {} + + protected: + ContentTypeWriter_T() : ContentTypeWriter(typeof()) {} + }; + + template + class BuiltinTypeWriter : public ContentTypeWriter_T { + String GetRuntimeReader(TargetPlatform targetPlatform) override { + String name = typeid(T).name(); + + switch (targetPlatform) + { + case xna::TargetPlatform::Windows: + name.append("::Windows"); + break; + default: + break; + } + + return name; + } + }; + + template + class ExternalReference { + public: + String FileName() const; + }; + + //Provides an implementation for many of the ContentCompiler methods including compilation, state tracking for shared resources and creation of the header type manifest. + class ContentWriter : public BinaryWriter { + public: + ContentWriter( + P_ContentCompiler& compiler, + P_Stream const& output, + TargetPlatform targetPlatform, + GraphicsProfile targetProfile, + bool compressContent, + String const& rootDirectory, + String const& referenceRelocationPath + ); + + //Gets the content build target platform. + constexpr TargetPlatform Target() const { return targetPlatform; } + //Gets or sets the target graphics profile. + constexpr GraphicsProfile TargetProfile() const { return targetProfile; } + + //Writes a single object preceded by a type identifier to the output binary. + template void WriteObject(T& value); + //Writes a single object to the output binary, using the specified type hint and writer worker. + template void WriteObject(T& value, ContentTypeWriter& writer); + //Writes a single object to the output binary as an instance of the specified type. + template void WriteRawObject(T& value); + //Writes a single object to the output binary using the specified writer worker. + template void WriteRawObject(T& value, ContentTypeWriter& typeWriter); + //Adds a shared reference to the output binary and records the object to be serialized later. + template void WriteSharedResource(T& value); + //Writes the name of an external file to the output binary. + template void WriteExternalReference(ExternalReference& reference); + + using BinaryWriter::Write; + + //Writes a Vector2 value. + void Write(Vector2 const& value); + //Writes a Vector3 value. + void Write(Vector3 const& value); + //Writes a Vector4 value. + void Write(Vector4 const& value); + //Writes a Matrix value. + void Write(Matrix const& value); + //Writes a Quaternion value. + void Write(Quaternion const& value); + //Writes a Color value. + void Write(Color const& value); + + inline void FlushOutput() { + WriteSharedResources(); + WriteHeader(); + WriteFinalOutput(); + } + + private: + template void InvokeWriter(T& value, ContentTypeWriter& writer); + P_ContentTypeWriter GetTypeWriter(Type const& type, Int& typeIndex); + void WriteSharedResources(); + void WriteHeader(); + void WriteFinalOutput(); + void WriteUncompressedOutput(); + void WriteCompressedOutput(); + void WriteVersionNumber(Ushort version); + + private: + P_ContentCompiler compiler{ nullptr }; + TargetPlatform targetPlatform{ TargetPlatform::Windows }; + GraphicsProfile targetProfile{ GraphicsProfile::HiDef }; + bool compressContent{ false }; + String rootDirectory; + String referenceRelocationPath; + P_Stream finalOutput{ nullptr }; + P_MemoryStream headerData{ nullptr }; + P_MemoryStream contentData{ nullptr }; + std::vector typeWriters; + std::map sharedResourceNames; + std::queue sharedResources; + std::map typeTable; + + private: + static constexpr Ushort XnbVersion = 5; + static constexpr Ushort XnbCompressedVersion = 32773; + static constexpr Ushort XnbVersionProfileMask = 32512; + static constexpr Int XnbVersionProfileShift = 8; + static constexpr Int XnbVersionOffset = 4; + static constexpr Int XnbFileSizeOffset = 6; + static constexpr Int XnbPrologueSize = 10; + inline static const String FilenameExt = ".xnb"; + }; + + template + class TypeHandlerFactory { + + }; + + class ContentTypeWriterFactory : public TypeHandlerFactory { + public: + std::vector Initialize() const { + std::vector writers; + + return writers; + } + }; + + // + // ContentTypeWriter + // + + template + void ContentWriter::WriteObject(T& value) { + if constexpr (XnaHelper::IsSmartPoint()) { + if (value == nullptr) { + Exception::Throw(Exception::ARGUMENT_IS_NULL); + } + } + + const auto type = typeof(); + Int _; + auto typeWriter = GetTypeWriter(*type, _); + + InvokeWriter(value, *typeWriter); + } + + template + void ContentWriter::WriteObject(T& value, ContentTypeWriter& writer) { + auto contentTypeWriter = reinterpret_cast*>(&writer); + + if (contentTypeWriter) { + contentTypeWriter->Write(*this, value); + } + else { + Object _value = value; + writer.Write(*this, _value); + } + } + + template + void ContentWriter::WriteRawObject(T& value) { + if constexpr (XnaHelper::IsSmartPoint()) { + if (value == nullptr) { + Exception::Throw(Exception::ARGUMENT_IS_NULL); + } + } + + const auto type = typeof(); + Int _; + auto typeWriter = GetTypeWriter(*type, _); + + InvokeWriter(value, *typeWriter); + } + + template + void ContentWriter::WriteRawObject(T& value, ContentTypeWriter& typeWriter) { + Exception::ThrowTIsNull(value); + + InvokeWriter(value, typeWriter); + } + + + template + void ContentWriter::WriteSharedResource(T& value) { + if constexpr (XnaHelper::IsSmartPoint()) { + if (value == nullptr) + Write7BitEncodedInt(0); + } + else { + Int num; + Object obj = value; + + if (!sharedResourceNames.contains(value)) { + num = sharedResourceNames.size() + 1; + sharedResourceNames.emplace(obj, num); + sharedResources.push(obj); + } + else { + num = sharedResourceNames[value]; + } + + Write7BitEncodedInt(num); + } + } + + + template + void ContentWriter::WriteExternalReference(ExternalReference& reference) { + const auto& filename1 = reference.FileName(); + + if (filename1.empty()) { + Write(""); + } + else { + String filename2; + + if (filename1.ends_with(FilenameExt)) + filename2 = filename1.substr(0, filename1.size() - FilenameExt.size()); + else + Exception::Throw(Exception::INVALID_OPERATION); + + if (!filename2.starts_with(rootDirectory)) + Exception::Throw(Exception::INVALID_OPERATION); + + + Exception::Throw(Exception::NOT_IMPLEMENTED); + } + } + + template + void ContentWriter::InvokeWriter(T& value, ContentTypeWriter& writer) { + auto contentTypeWriter = reinterpret_cast*>(&writer); + + if (contentTypeWriter) { + contentTypeWriter->Write(*this, value); + } + else { + Object obj = value; + writer.Write(*this, obj); + } + } +} + +#endif \ No newline at end of file diff --git a/includes/xna/default.hpp b/includes/xna/default.hpp index a1ed6e5..7608349 100644 --- a/includes/xna/default.hpp +++ b/includes/xna/default.hpp @@ -104,6 +104,12 @@ namespace xna { return std::make_unique<_Ty>(std::forward<_Types>(_Args)...); } + // + // Hash value + // + + using HashValue = size_t; + // // Forward // @@ -199,15 +205,16 @@ namespace xna { using P_DepthStencilState = sptr; using P_GraphicsAdapter = sptr; using P_GraphicsDevice = sptr; - using P_RasterizerState = sptr; + using P_FileStream = sptr; + using P_MemoryStream = sptr; using P_PresentationParameters = sptr; + using P_RenderTarget2D = sptr; using P_SamplerStateCollection = sptr; using P_Stream = sptr; - using P_MemoryStream = sptr; - using P_FileStream = sptr; + using P_RasterizerState = sptr; + using P_Type = sptr; using P_Texture = sptr; using P_Texture2D = sptr; - using P_RenderTarget2D = sptr; } diff --git a/sources/pipeline/CMakeLists.txt b/sources/pipeline/CMakeLists.txt index dfcb839..78994d4 100644 --- a/sources/pipeline/CMakeLists.txt +++ b/sources/pipeline/CMakeLists.txt @@ -4,13 +4,12 @@ # Add source to this project's executable. add_library (Xn65Pipeline STATIC -"discard.cpp" +"writer.cpp" +"compiler.cpp" ) if (CMAKE_VERSION VERSION_GREATER 3.12) set_property(TARGET Xn65Pipeline PROPERTY CXX_STANDARD 20) endif() -find_package(directxtk CONFIG REQUIRED) - #target_link_libraries(Xn65Pipeline) diff --git a/sources/pipeline/compiler.cpp b/sources/pipeline/compiler.cpp new file mode 100644 index 0000000..30b8ed3 --- /dev/null +++ b/sources/pipeline/compiler.cpp @@ -0,0 +1,38 @@ +#include "pipeline/compiler.hpp" +#include "pipeline/writer.hpp" + +namespace xna { + ContentCompiler::ContentCompiler() { + const auto writers = typeWriterFactory->Initialize(); + + for (auto& writer : writers) + AddTypeWriter(writer); + + for (auto& dic : writerInstances) { + auto& writer = dic.second; + AddTypeWriter(writer); + } + } + + void ContentCompiler::Compile( + P_Stream const& output, + Object& value, + TargetPlatform targetPlatform, + GraphicsProfile targetProfile, + bool compressContent, + String const& rootDirectory, + String const& referenceRelocationPath) { + if (compressContent) + compressContent = ShouldCompressContent(targetPlatform, value); + + auto _this = shared_from_this(); + + auto contentWriter = unew( + _this, output, targetPlatform, + targetProfile, compressContent, + rootDirectory, referenceRelocationPath); + + contentWriter->WriteObject(value); + contentWriter->FlushOutput(); + } +} \ No newline at end of file diff --git a/sources/pipeline/discard.cpp b/sources/pipeline/discard.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/sources/pipeline/writer.cpp b/sources/pipeline/writer.cpp new file mode 100644 index 0000000..1c52a5b --- /dev/null +++ b/sources/pipeline/writer.cpp @@ -0,0 +1,171 @@ +#include "pipeline/writer.hpp" +#include "pipeline/compiler.hpp" + +namespace xna { + + // + // ContentWriter + // + + ContentWriter::ContentWriter( + P_ContentCompiler& compiler, + P_Stream const& output, + TargetPlatform targetPlatform, + GraphicsProfile targetProfile, + bool compressContent, + String const& rootDirectory, + String const& referenceRelocationPath + ) : compiler(compiler), + targetPlatform(targetPlatform), + targetProfile(targetProfile), + compressContent(compressContent), + rootDirectory(rootDirectory), + referenceRelocationPath(referenceRelocationPath), + finalOutput(output) + { + headerData = snew(); + contentData = snew(); + OutStream = reinterpret_pointer_cast(contentData); + } + + P_ContentTypeWriter ContentWriter::GetTypeWriter(Type const& type, Int& typeIndex) { + const auto& hash = type.GetHashCode(); + + if (typeTable.contains(hash)) { + typeIndex = typeTable[hash]; + return typeWriters[typeIndex]; + } + + std::vector dependecies; + auto typeWriter = compiler->GetTypeWriter(type, dependecies); + typeIndex = typeWriters.size(); + + typeWriters.push_back(typeWriter); + typeTable.emplace(type.GetHashCode(), typeIndex); + + for (size_t i = 0; i < dependecies.size(); ++i) { + const auto& type1 = dependecies[i]; + + if (type1 != typeof()) + { + Int _; + GetTypeWriter(*type1, _); + } + } + + return typeWriter; + } + + void ContentWriter::WriteSharedResources() { + while (sharedResources.size() > 0) { + sharedResources.pop(); + auto& res = sharedResources.front(); + WriteObject(res); + } + } + + void ContentWriter::WriteHeader() { + OutStream = reinterpret_pointer_cast(headerData); + Write7BitEncodedInt(static_cast(typeWriters.size())); + + for (size_t i = 0; i < typeWriters.size(); ++i) { + auto& typeWriter = typeWriters[i]; + + Write(typeWriter->GetRuntimeReader(targetPlatform)); + Write(typeWriter->TypeVersion()); + } + + Write7BitEncodedInt(static_cast(sharedResourceNames.size())); + } + + void ContentWriter::WriteFinalOutput() { + OutStream = finalOutput; + + Write((Byte)88); + Write((Byte)78); + Write((Byte)66); + + if (targetPlatform == TargetPlatform::Windows) + Write((Byte)119); + else + Exception::Throw(Exception::NOT_IMPLEMENTED); + + if (compressContent) + WriteCompressedOutput(); + else + WriteUncompressedOutput(); + } + + void ContentWriter::WriteUncompressedOutput() { + WriteVersionNumber((Ushort)5); + + const auto length1 = static_cast(headerData->Length()); + const auto length2 = static_cast(contentData->Length()); + + Write(10 + length1 + length2); + + OutStream->Write(headerData->_buffer, 0, length1); + OutStream->Write(contentData->_buffer, 0, length2); + } + + void ContentWriter::WriteCompressedOutput() { + Exception::Throw(Exception::NOT_IMPLEMENTED); + } + + void ContentWriter::WriteVersionNumber(Ushort version) { + version |= static_cast(static_cast(targetProfile) << 8 & 32512); + Write(version); + } + + void ContentWriter::Write(Vector2 const& value) { + Write(value.X); + Write(value.Y); + } + + void ContentWriter::Write(Vector3 const& value) { + Write(value.X); + Write(value.Y); + Write(value.Z); + } + + void ContentWriter::Write(Vector4 const& value) { + Write(value.X); + Write(value.Y); + Write(value.Z); + Write(value.W); + } + + void ContentWriter::Write(Matrix const& value) { + Write(value.M11); + Write(value.M12); + Write(value.M13); + Write(value.M14); + Write(value.M21); + Write(value.M22); + Write(value.M23); + Write(value.M24); + Write(value.M31); + Write(value.M32); + Write(value.M33); + Write(value.M34); + Write(value.M41); + Write(value.M42); + Write(value.M43); + Write(value.M44); + } + + void ContentWriter::Write(Quaternion const& value) { + Write(value.X); + Write(value.Y); + Write(value.Z); + Write(value.W); + } + + void ContentWriter::Write(Color const& value) { + Write(value.PackedValue()); + } + + // + // + // +} \ No newline at end of file