// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #include #include #include #include namespace Nz { Buffer::Buffer(BufferType type) : m_type(type), m_usage(0), m_size(0) { } Buffer::Buffer(BufferType type, UInt32 size, DataStorage storage, BufferUsageFlags usage) : Buffer(type) { ErrorFlags flags(ErrorFlag_ThrowException, true); Create(size, storage, usage); } Buffer::~Buffer() { OnBufferRelease(this); Destroy(); } bool Buffer::CopyContent(const BufferRef& buffer) { NazaraAssert(m_impl, "Invalid buffer"); NazaraAssert(!buffer && !buffer->IsValid(), "Invalid source buffer"); BufferMapper mapper(*buffer, BufferAccess_ReadOnly); return Fill(mapper.GetPointer(), 0, buffer->GetSize()); } bool Buffer::Create(UInt32 size, DataStorage storage, BufferUsageFlags usage) { Destroy(); // Notre buffer est-il supporté ? if (!IsStorageSupported(storage)) { NazaraError("Buffer storage not supported"); return false; } std::unique_ptr impl(s_bufferFactories[storage](this, m_type)); if (!impl->Initialize(size, usage)) { NazaraError("Failed to create buffer"); return false; } m_impl = std::move(impl); m_size = size; m_usage = usage; return true; // Si on arrive ici c'est que tout s'est bien passé. } void Buffer::Destroy() { if (m_impl) { OnBufferDestroy(this); m_impl.reset(); } } bool Buffer::Fill(const void* data, UInt32 offset, UInt32 size) { NazaraAssert(m_impl, "Invalid buffer"); NazaraAssert(offset + size <= m_size, "Exceeding buffer size"); return m_impl->Fill(data, offset, (size == 0) ? m_size - offset : size); } void* Buffer::Map(BufferAccess access, UInt32 offset, UInt32 size) { NazaraAssert(m_impl, "Invalid buffer"); NazaraAssert(offset + size <= m_size, "Exceeding buffer size"); return m_impl->Map(access, offset, (size == 0) ? m_size - offset : size); } void* Buffer::Map(BufferAccess access, UInt32 offset, UInt32 size) const { NazaraAssert(m_impl, "Invalid buffer"); NazaraAssert(access == BufferAccess_ReadOnly, "Buffer access must be read-only when used const"); NazaraAssert(offset + size <= m_size, "Exceeding buffer size"); return m_impl->Map(access, offset, (size == 0) ? m_size - offset : size); } bool Buffer::SetStorage(DataStorage storage) { NazaraAssert(m_impl, "Invalid buffer"); if (HasStorage(storage)) return true; if (!IsStorageSupported(storage)) { NazaraError("Storage not supported"); return false; } void* ptr = m_impl->Map(BufferAccess_ReadOnly, 0, m_size); if (!ptr) { NazaraError("Failed to map buffer"); return false; } CallOnExit unmapMyImpl([this]() { m_impl->Unmap(); }); std::unique_ptr impl(s_bufferFactories[storage](this, m_type)); if (!impl->Initialize(m_size, m_usage)) { NazaraError("Failed to create buffer"); return false; } if (!impl->Fill(ptr, 0, m_size)) { NazaraError("Failed to fill buffer"); return false; } unmapMyImpl.CallAndReset(); m_impl = std::move(impl); return true; } void Buffer::Unmap() const { NazaraAssert(m_impl, "Invalid buffer"); if (!m_impl->Unmap()) NazaraWarning("Failed to unmap buffer (it's content may be undefined)"); ///TODO: Unexpected ? } bool Buffer::IsStorageSupported(DataStorage storage) { return s_bufferFactories[storage] != nullptr; } void Buffer::SetBufferFactory(DataStorage storage, BufferFactory func) { s_bufferFactories[storage] = func; } bool Buffer::Initialize() { SetBufferFactory(DataStorage_Software, [](Buffer* parent, BufferType type) -> AbstractBuffer* { return new SoftwareBuffer(parent, type); }); return true; } void Buffer::Uninitialize() { std::fill(s_bufferFactories.begin(), s_bufferFactories.end(), nullptr); } std::array Buffer::s_bufferFactories; }