diff --git a/CMakeLists.txt b/CMakeLists.txt index 05f3354..ea27892 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,10 @@ set(EXAMPLES 12-simplecompute ) +set(ADDITIONS + miniGLRender +) + find_package(OpenMP) if (OPENMP_FOUND) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") @@ -94,6 +98,32 @@ foreach(EXAMPLE ${EXAMPLES}) endif(MSVC) endforeach(EXAMPLE) +foreach(ADDITION ${ADDITIONS}) + add_executable(${ADDITION} WIN32 + src/${ADDITION}/miniRenderApp.cpp + src/${ADDITION}/tr_common.cpp + src/${ADDITION}/tr_common.h + src/${ADDITION}/common.cpp + src/${ADDITION}/common.h + src/${ADDITION}/math_common.cpp + src/${ADDITION}/math_common.h + src/${ADDITION}/thread.cpp + src/${ADDITION}/thread.h + src/${ADDITION}/renderSystem.cpp + src/${ADDITION}/renderSystem.h + src/${ADDITION}/bufferObjects.cpp + src/${ADDITION}/bufferObjects.h + src/${ADDITION}/vertexCache.cpp + src/${ADDITION}/vertexCache.h +) + + set_property(TARGET ${ADDITION} PROPERTY DEBUG_POSTFIX _d) + target_link_libraries(${ADDITION} ${COMMON_LIBS}) + if(MSVC) + configure_file(${PROJECT_SOURCE_DIR}/build/templates/vs2013.vcxproj.user.in ${CMAKE_CURRENT_BINARY_DIR}/${ADDITION}.vcxproj.user @ONLY) + endif(MSVC) +endforeach(ADDITION) + IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_LINUX") ENDIF (${CMAKE_SYSTEM_NAME} MATCHES "Linux") diff --git a/src/miniGLRender/bufferObjects.cpp b/src/miniGLRender/bufferObjects.cpp new file mode 100644 index 0000000..10947bf --- /dev/null +++ b/src/miniGLRender/bufferObjects.cpp @@ -0,0 +1,423 @@ +#include "bufferObjects.h" + + +//static const GLenum bufferUsage = GL_STATIC_DRAW_ARB; +static const GLenum bufferUsage = GL_DYNAMIC_DRAW; + +bool IsWriteCombined(void* base) +{ + MEMORY_BASIC_INFORMATION info; + SIZE_T size = VirtualQueryEx(GetCurrentProcess(), base, &info, sizeof(info)); + if (size == 0) { + DWORD error = GetLastError(); + error = error; + return false; + } + bool isWriteCombined = ((info.AllocationProtect & PAGE_WRITECOMBINE) != 0); + return isWriteCombined; +} + +// qqVertexBuffer +qqVertexBuffer::qqVertexBuffer() +{ + size = 0; + offsetInOtherBuffer = OWNS_BUFFER_FLAG; + apiObject = 0; + SetUnmapped(); +} + +qqVertexBuffer::~qqVertexBuffer() +{ + FreeBufferObject(); +} + +bool qqVertexBuffer::AllocBufferObject(const void* data, int allocSize) +{ + assert(apiObject == NULL); + assert_16_byte_aligned(data); + + if (allocSize <= 0) { + return false; + } + + size = allocSize; + + bool allocationFailed = false; + + int numBytes = GetAllocedSize(); + + + // clear out any previous error + glGetError(); + + GLuint bufferObject = 0xFFFF; + glGenBuffers(1, &bufferObject); + if (bufferObject == 0xFFFF) { + //idLib::FatalError("idVertexBuffer::AllocBufferObject: failed"); + return false; + } + glBindBuffer(GL_ARRAY_BUFFER, bufferObject); + + // these are rewritten every frame + glBufferData(GL_ARRAY_BUFFER, numBytes, NULL, bufferUsage); + apiObject = (bufferObject); + + GLenum err = glGetError(); + if (err == GL_OUT_OF_MEMORY) { + //idLib::Warning("idVertexBuffer::AllocBufferObject: allocation failed"); + allocationFailed = true; + } + + // copy the data + if (data != NULL) { + Update(data, allocSize); + } + + return !allocationFailed; +} + +void qqVertexBuffer::FreeBufferObject() +{ + if (IsMapped()) { + UnmapBuffer(); + } + + // if this is a sub-allocation inside a larger buffer, don't actually free anything. + if (OwnsBuffer() == false) { + ClearWithoutFreeing(); + return; + } + + if (apiObject == NULL) { + return; + } + + //if (r_showBuffers.GetBool()) { + // idLib::Printf("vertex buffer free %p, api %p (%i bytes)\n", this, GetAPIObject(), GetSize()); + //} + + GLuint bufferObject = (apiObject); + glDeleteBuffers(1, &bufferObject); + + ClearWithoutFreeing(); +} + +void qqVertexBuffer::Reference(const qqVertexBuffer& other) +{ + assert(IsMapped() == false); + //assert( other.IsMapped() == false ); // this happens when building idTriangles while at the same time setting up idDrawVerts + assert(other.GetAPIObject() != NULL); + assert(other.GetSize() > 0); + + FreeBufferObject(); + size = other.GetSize(); // this strips the MAPPED_FLAG + offsetInOtherBuffer = other.GetOffset(); // this strips the OWNS_BUFFER_FLAG + apiObject = other.apiObject; + assert(OwnsBuffer() == false); +} + +void qqVertexBuffer::Reference(const qqVertexBuffer& other, int refOffset, int refSize) +{ + assert(IsMapped() == false); + //assert( other.IsMapped() == false ); // this happens when building idTriangles while at the same time setting up idDrawVerts + assert(other.GetAPIObject() != NULL); + assert(refOffset >= 0); + assert(refSize >= 0); + assert(refOffset + refSize <= other.GetSize()); + + FreeBufferObject(); + size = refSize; + offsetInOtherBuffer = other.GetOffset() + refOffset; + apiObject = other.apiObject; + assert(OwnsBuffer() == false); +} + +void qqVertexBuffer::Update(const void* data, int updateSize) const +{ + assert(apiObject != NULL); + assert(IsMapped() == false); + assert_16_byte_aligned(data); + assert((GetOffset() & 15) == 0); + + if (updateSize > size) { + //idLib::FatalError("idVertexBuffer::Update: size overrun, %i > %i\n", updateSize, GetSize()); + return; + } + + int numBytes = (updateSize + 15) & ~15; + + GLuint bufferObject = apiObject; + + glBindBuffer(GL_ARRAY_BUFFER, bufferObject); + glBufferSubData(GL_ARRAY_BUFFER, GetOffset(), (GLsizeiptr)numBytes, data); + /* + void * buffer = MapBuffer( BM_WRITE ); + CopyBuffer( (byte *)buffer + GetOffset(), (byte *)data, numBytes ); + UnmapBuffer(); + */ +} + +void* qqVertexBuffer::MapBuffer(bufferMapType_t mapType) const +{ + assert(apiObject != NULL); + assert(IsMapped() == false); + + void* buffer = NULL; + + GLuint bufferObject = (apiObject); + + glBindBuffer(GL_ARRAY_BUFFER, bufferObject); + if (mapType == BM_READ) { + //buffer = qglMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB ); + buffer = glMapBufferRange(GL_ARRAY_BUFFER, 0, GetAllocedSize(), GL_MAP_READ_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + if (buffer != NULL) { + buffer = (byte*)buffer + GetOffset(); + } + } + else if (mapType == BM_WRITE) { + //buffer = qglMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB ); + buffer = glMapBufferRange(GL_ARRAY_BUFFER, 0, GetAllocedSize(), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + if (buffer != NULL) { + buffer = (byte*)buffer + GetOffset(); + } + assert(IsWriteCombined(buffer)); + } + else { + assert(false); + return nullptr; + } + + SetMapped(); + + if (buffer == NULL) { + //idLib::FatalError("idVertexBuffer::MapBuffer: failed"); + return nullptr; + } + return buffer; +} + +void qqVertexBuffer::UnmapBuffer() const +{ + assert(apiObject != NULL); + assert(IsMapped()); + + GLuint bufferObject = (apiObject); + glBindBuffer(GL_ARRAY_BUFFER, bufferObject); + if (!glUnmapBuffer(GL_ARRAY_BUFFER)) { + //idLib::Printf("idVertexBuffer::UnmapBuffer failed\n"); + } + + SetUnmapped(); +} + +void qqVertexBuffer::ClearWithoutFreeing() { + size = 0; + offsetInOtherBuffer = OWNS_BUFFER_FLAG; + apiObject = 0; +} + + +// qqIndexBuffer +qqIndexBuffer::qqIndexBuffer() +{ + size = 0; + offsetInOtherBuffer = OWNS_BUFFER_FLAG; + apiObject = NULL; + SetUnmapped(); +} + +qqIndexBuffer::~qqIndexBuffer() +{ + FreeBufferObject(); +} + +bool qqIndexBuffer::AllocBufferObject(const void* data, int allocSize) +{ + assert(apiObject == NULL); + assert_16_byte_aligned(data); + + if (allocSize <= 0) { + //idLib::Error("qqIndexBuffer::AllocBufferObject: allocSize = %i", allocSize); + return false; + } + + size = allocSize; + + bool allocationFailed = false; + + int numBytes = GetAllocedSize(); + + + // clear out any previous error + glGetError(); + + GLuint bufferObject = 0xFFFF; + glGenBuffers(1, &bufferObject); + if (bufferObject == 0xFFFF) { + GLenum error = glGetError(); + //idLib::FatalError("qqIndexBuffer::AllocBufferObject: failed - GL_Error %d", error); + return false; + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObject); + + // these are rewritten every frame + glBufferData(GL_ELEMENT_ARRAY_BUFFER, numBytes, NULL, bufferUsage); + apiObject = (bufferObject); + + GLenum err = glGetError(); + if (err == GL_OUT_OF_MEMORY) + { + //idLib::Warning("qqIndexBuffer:AllocBufferObject: allocation failed"); + allocationFailed = true; + } + + //if (r_showBuffers.GetBool()) { + // idLib::Printf("index buffer alloc %p, api %p (%i bytes)\n", this, GetAPIObject(), GetSize()); + //} + + // copy the data + if (data != NULL) { + Update(data, allocSize); + } + + return !allocationFailed; +} + +void qqIndexBuffer::FreeBufferObject() +{ + if (IsMapped()) { + UnmapBuffer(); + } + + // if this is a sub-allocation inside a larger buffer, don't actually free anything. + if (OwnsBuffer() == false) { + ClearWithoutFreeing(); + return; + } + + if (apiObject == NULL) { + return; + } + + //if (r_showBuffers.GetBool()) { + // idLib::Printf("index buffer free %p, api %p (%i bytes)\n", this, GetAPIObject(), GetSize()); + //} + + GLuint bufferObject = (apiObject); + glDeleteBuffers(1, &bufferObject); + + ClearWithoutFreeing(); +} + +void qqIndexBuffer::Reference(const qqIndexBuffer& other) +{ + assert(IsMapped() == false); + //assert( other.IsMapped() == false ); // this happens when building idTriangles while at the same time setting up triIndex_t + assert(other.GetAPIObject() != NULL); + assert(other.GetSize() > 0); + + FreeBufferObject(); + size = other.GetSize(); // this strips the MAPPED_FLAG + offsetInOtherBuffer = other.GetOffset(); // this strips the OWNS_BUFFER_FLAG + apiObject = other.apiObject; + assert(OwnsBuffer() == false); +} + +void qqIndexBuffer::Reference(const qqIndexBuffer& other, int refOffset, int refSize) +{ + assert(IsMapped() == false); + //assert( other.IsMapped() == false ); // this happens when building idTriangles while at the same time setting up triIndex_t + assert(other.GetAPIObject() != NULL); + assert(refOffset >= 0); + assert(refSize >= 0); + assert(refOffset + refSize <= other.GetSize()); + + FreeBufferObject(); + size = refSize; + offsetInOtherBuffer = other.GetOffset() + refOffset; + apiObject = other.apiObject; + assert(OwnsBuffer() == false); +} + +void qqIndexBuffer::Update(const void* data, int updateSize) const +{ + + assert(apiObject != NULL); + assert(IsMapped() == false); + assert_16_byte_aligned(data); + assert((GetOffset() & 15) == 0); + + if (updateSize > size) { + //idLib::FatalError("qqIndexBuffer::Update: size overrun, %i > %i\n", updateSize, GetSize()); + return; + } + + int numBytes = (updateSize + 15) & ~15; + + GLuint bufferObject = (apiObject); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObject); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, GetOffset(), (GLsizeiptr)numBytes, data); + /* + void * buffer = MapBuffer( BM_WRITE ); + CopyBuffer( (byte *)buffer + GetOffset(), (byte *)data, numBytes ); + UnmapBuffer(); + */ +} + +void* qqIndexBuffer::MapBuffer(bufferMapType_t mapType) const +{ + + assert(apiObject != NULL); + assert(IsMapped() == false); + + void* buffer = NULL; + + GLuint bufferObject = (apiObject); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObject); + if (mapType == BM_READ) { + //buffer = qglMapBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB ); + buffer = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, GetAllocedSize(), GL_MAP_READ_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + if (buffer != NULL) { + buffer = (byte*)buffer + GetOffset(); + } + } + else if (mapType == BM_WRITE) { + //buffer = qglMapBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB ); + buffer = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, GetAllocedSize(), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + if (buffer != NULL) { + buffer = (byte*)buffer + GetOffset(); + } + assert(IsWriteCombined(buffer)); + } + else { + assert(false); + } + + SetMapped(); + + if (buffer == NULL) { + //idLib::FatalError("qqIndexBuffer::MapBuffer: failed"); + } + return buffer; +} + +void qqIndexBuffer::UnmapBuffer() const +{ + assert(apiObject != NULL); + assert(IsMapped()); + + GLuint bufferObject = (apiObject); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObject); + if (!glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER)) { + //idLib::Printf("qqIndexBuffer::UnmapBuffer failed\n"); + } + + SetUnmapped(); +} + +void qqIndexBuffer::ClearWithoutFreeing() +{ + size = 0; + offsetInOtherBuffer = OWNS_BUFFER_FLAG; + apiObject = NULL; +} diff --git a/src/miniGLRender/bufferObjects.h b/src/miniGLRender/bufferObjects.h new file mode 100644 index 0000000..52d8c2d --- /dev/null +++ b/src/miniGLRender/bufferObjects.h @@ -0,0 +1,108 @@ +#ifndef __BUFFEROBJECT_H__ +#define __BUFFEROBJECT_H__ + +#include "tr_common.h" + + +enum bufferMapType_t +{ + BM_READ, // map for reading + BM_WRITE // map for writing +}; + +/* +================================================ +qqVertexBuffer +================================================ +*/ +class qqVertexBuffer +{ +public: + qqVertexBuffer(); + ~qqVertexBuffer(); + + // Allocate or free the buffer. + bool AllocBufferObject(const void* data, int allocSize); + void FreeBufferObject(); + + // Make this buffer a reference to another buffer. + void Reference(const qqVertexBuffer& other); + void Reference(const qqVertexBuffer& other, int refOffset, int refSize); + + // Copies data to the buffer. 'size' may be less than the originally allocated size. + void Update(const void* data, int updateSize) const; + + void* MapBuffer(bufferMapType_t mapType) const; + qqDrawVert* MapVertexBuffer(bufferMapType_t mapType) const { return static_cast(MapBuffer(mapType)); } + void UnmapBuffer() const; + bool IsMapped() const { return (size & MAPPED_FLAG) != 0; } + + int GetSize() const { return (size & ~MAPPED_FLAG); } + int GetAllocedSize() const { return ((size & ~MAPPED_FLAG) + 15) & ~15; } + unsigned int GetAPIObject() const { return apiObject; } + int GetOffset() const { return (offsetInOtherBuffer & ~OWNS_BUFFER_FLAG); } + +private: + int size; // size in bytes + int offsetInOtherBuffer; // offset in bytes + unsigned int apiObject; + + // sizeof() confuses typeinfo... + static const int MAPPED_FLAG = 1 << (4 /* sizeof( int ) */ * 8 - 1); + static const int OWNS_BUFFER_FLAG = 1 << (4 /* sizeof( int ) */ * 8 - 1); + +private: + void ClearWithoutFreeing(); + void SetMapped() const { const_cast(size) |= MAPPED_FLAG; } + void SetUnmapped() const { const_cast(size) &= ~MAPPED_FLAG; } + bool OwnsBuffer() const { return ((offsetInOtherBuffer & OWNS_BUFFER_FLAG) != 0); } + + DISALLOW_COPY_AND_ASSIGN(qqVertexBuffer); +}; + +class qqIndexBuffer +{ +public: + qqIndexBuffer(); + ~qqIndexBuffer(); + + // Allocate or free the buffer. + bool AllocBufferObject(const void* data, int allocSize); + void FreeBufferObject(); + + // Make this buffer a reference to another buffer. + void Reference(const qqIndexBuffer& other); + void Reference(const qqIndexBuffer& other, int refOffset, int refSize); + + // Copies data to the buffer. 'size' may be less than the originally allocated size. + void Update(const void* data, int updateSize) const; + + void* MapBuffer(bufferMapType_t mapType) const; + triIndex_t* MapIndexBuffer(bufferMapType_t mapType) const { return static_cast(MapBuffer(mapType)); } + void UnmapBuffer() const; + bool IsMapped() const { return (size & MAPPED_FLAG) != 0; } + + int GetSize() const { return (size & ~MAPPED_FLAG); } + int GetAllocedSize() const { return ((size & ~MAPPED_FLAG) + 15) & ~15; } + unsigned int GetAPIObject() const { return apiObject; } + int GetOffset() const { return (offsetInOtherBuffer & ~OWNS_BUFFER_FLAG); } + +private: + int size; // size in bytes + int offsetInOtherBuffer; // offset in bytes + unsigned int apiObject; + + // sizeof() confuses typeinfo... + static const int MAPPED_FLAG = 1 << (4 /* sizeof( int ) */ * 8 - 1); + static const int OWNS_BUFFER_FLAG = 1 << (4 /* sizeof( int ) */ * 8 - 1); + +private: + void ClearWithoutFreeing(); + void SetMapped() const { const_cast(size) |= MAPPED_FLAG; } + void SetUnmapped() const { const_cast(size) &= ~MAPPED_FLAG; } + bool OwnsBuffer() const { return ((offsetInOtherBuffer & OWNS_BUFFER_FLAG) != 0); } + + DISALLOW_COPY_AND_ASSIGN(qqIndexBuffer); +}; + +#endif diff --git a/src/miniGLRender/common.cpp b/src/miniGLRender/common.cpp new file mode 100644 index 0000000..cc17f0d --- /dev/null +++ b/src/miniGLRender/common.cpp @@ -0,0 +1,3 @@ +#include "common.h" + + diff --git a/src/miniGLRender/common.h b/src/miniGLRender/common.h new file mode 100644 index 0000000..fdad426 --- /dev/null +++ b/src/miniGLRender/common.h @@ -0,0 +1,46 @@ +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#include +#include + +// A macro to disallow the copy constructor and operator= functions +// NOTE: The macro contains "private:" so all members defined after it will be private until +// public: or protected: is specified. +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ +private: \ + TypeName(const TypeName&); \ + void operator=(const TypeName&); + +// assert +#define assert_2_byte_aligned( ptr ) assert( ( ((UINT_PTR)(ptr)) & 1 ) == 0 ) +#define assert_4_byte_aligned( ptr ) assert( ( ((UINT_PTR)(ptr)) & 3 ) == 0 ) +#define assert_8_byte_aligned( ptr ) assert( ( ((UINT_PTR)(ptr)) & 7 ) == 0 ) +#define assert_16_byte_aligned( ptr ) assert( ( ((UINT_PTR)(ptr)) & 15 ) == 0 ) +#define assert_32_byte_aligned( ptr ) assert( ( ((UINT_PTR)(ptr)) & 31 ) == 0 ) +#define assert_64_byte_aligned( ptr ) assert( ( ((UINT_PTR)(ptr)) & 63 ) == 0 ) +#define assert_128_byte_aligned( ptr ) assert( ( ((UINT_PTR)(ptr)) & 127 ) == 0 ) +#define assert_aligned_to_type_size( ptr ) assert( ( ((UINT_PTR)(ptr)) & ( sizeof( (ptr)[0] ) - 1 ) ) == 0 ) + + +typedef unsigned char byte; // 8 bits +typedef unsigned short word; // 16 bits +typedef unsigned int dword; // 32 bits +typedef unsigned int uint; +typedef unsigned long ulong; + +typedef signed char int8; +typedef unsigned char uint8; +typedef short int int16; +typedef unsigned short int uint16; +typedef int int32; +typedef unsigned int uint32; +typedef long long int64; +typedef unsigned long long uint64; + + +// halfFloat_t +typedef unsigned short halfFloat_t; + + +#endif // __COMMON_H__ diff --git a/src/miniGLRender/math_common.cpp b/src/miniGLRender/math_common.cpp new file mode 100644 index 0000000..b4bcbd0 --- /dev/null +++ b/src/miniGLRender/math_common.cpp @@ -0,0 +1,12 @@ +#include "math_common.h" + +// qqVec3 +qqVec3::qqVec3() +{ + x = y = z = 0.0f; +} + +qqVec3::~qqVec3() +{ + +} diff --git a/src/miniGLRender/math_common.h b/src/miniGLRender/math_common.h new file mode 100644 index 0000000..71d0486 --- /dev/null +++ b/src/miniGLRender/math_common.h @@ -0,0 +1,16 @@ +#ifndef __MATH_COMMON_H__ +#define __MATH_COMMON_H__ + + +// qqVec3 +class qqVec3 +{ +public: + qqVec3(); + ~qqVec3(); + +public: + float x, y, z; +}; + +#endif // __MATH_COMMON_H__ diff --git a/src/miniGLRender/miniRenderApp.cpp b/src/miniGLRender/miniRenderApp.cpp new file mode 100644 index 0000000..a56e2bd --- /dev/null +++ b/src/miniGLRender/miniRenderApp.cpp @@ -0,0 +1,23 @@ + +#include +#include + +void test_gl() +{ + gl3wInit(); + + GLint i = 10; + i++; + + glCullFace(0); + glDrawArrays(GL_TRIANGLES, 0, 0); +} + +int WINAPI WinMain(HINSTANCE hInstance, // Instance + HINSTANCE hPrevInstance, // Previous Instance + LPSTR lpCmdLine, // Command Line Parameters + int nCmdShow) // Window Show State +{ + return 0; +} + diff --git a/src/miniGLRender/renderSystem.cpp b/src/miniGLRender/renderSystem.cpp new file mode 100644 index 0000000..a6c9f78 --- /dev/null +++ b/src/miniGLRender/renderSystem.cpp @@ -0,0 +1,2 @@ +#include "renderSystem.h" + diff --git a/src/miniGLRender/renderSystem.h b/src/miniGLRender/renderSystem.h new file mode 100644 index 0000000..1598354 --- /dev/null +++ b/src/miniGLRender/renderSystem.h @@ -0,0 +1,18 @@ +#ifndef __RENDER_SYSTEM_H__ +#define __RENDER_SYSTEM_H__ + +#include "tr_common.h" + +// qqRenderSystem +class qqRenderSystem +{ +public: + + virtual ~qqRenderSystem() {} + virtual void Init() = 0; + virtual void Shutdown() = 0; + + virtual const emptyCommand_t* SwapCommandBuffers(uint64* frontEndMicroSec, uint64* backEndMicroSec, uint64* shadowMicroSec, uint64* gpuMicroSec) = 0; + +}; +#endif // __RENDER_SYSTEM_H__ diff --git a/src/miniGLRender/thread.cpp b/src/miniGLRender/thread.cpp new file mode 100644 index 0000000..bedd001 --- /dev/null +++ b/src/miniGLRender/thread.cpp @@ -0,0 +1,23 @@ +#include "thread.h" +#include + +//// qqSysInterlockedInteger +//interlockedInt_t qqSysInterlockedInteger::Sys_InterlockedIncrement(interlockedInt_t& value) +//{ +// return InterlockedIncrementAcquire(&value); +//} +// +//interlockedInt_t qqSysInterlockedInteger::Sys_InterlockedDecrement(interlockedInt_t& value) +//{ +// return InterlockedDecrementRelease(&value); +//} +// +//interlockedInt_t qqSysInterlockedInteger::Sys_InterlockedAdd(interlockedInt_t& value, interlockedInt_t i) +//{ +// return InterlockedExchangeAdd(&value, i) + i; +//} +// +//interlockedInt_t qqSysInterlockedInteger::Sys_InterlockedSub(interlockedInt_t& value, interlockedInt_t i) +//{ +// return InterlockedExchangeAdd(&value, -i) - i; +//} diff --git a/src/miniGLRender/thread.h b/src/miniGLRender/thread.h new file mode 100644 index 0000000..9e52871 --- /dev/null +++ b/src/miniGLRender/thread.h @@ -0,0 +1,27 @@ +#ifndef __THREAD_H__ +#define __THREAD_H__ + +typedef int interlockedInt_t; + +class qqSysInterlockedInteger +{ +public: + qqSysInterlockedInteger() : value(0) {} + + int Increment() { return Sys_InterlockedIncrement(value); } + int Decrement() { return Sys_InterlockedDecrement(value); } + int Add(int v) { return Sys_InterlockedAdd(value, (interlockedInt_t)v); } + int Sub(int v) { return Sys_InterlockedSub(value, (interlockedInt_t)v); } + int GetValue() const { return value; } + void SetValue(int v) { value = (interlockedInt_t)v; } + +private: + interlockedInt_t Sys_InterlockedIncrement(interlockedInt_t& value); + interlockedInt_t Sys_InterlockedDecrement(interlockedInt_t& value); + interlockedInt_t Sys_InterlockedAdd(interlockedInt_t& value, interlockedInt_t i); + interlockedInt_t Sys_InterlockedSub(interlockedInt_t& value, interlockedInt_t i); + + interlockedInt_t value; +}; + +#endif // __COMMON_H__ diff --git a/src/miniGLRender/tr_common.cpp b/src/miniGLRender/tr_common.cpp new file mode 100644 index 0000000..cdba0ed --- /dev/null +++ b/src/miniGLRender/tr_common.cpp @@ -0,0 +1 @@ +#include "tr_common.h" diff --git a/src/miniGLRender/tr_common.h b/src/miniGLRender/tr_common.h new file mode 100644 index 0000000..98ad955 --- /dev/null +++ b/src/miniGLRender/tr_common.h @@ -0,0 +1,56 @@ +#ifndef __TR_COMMON_H__ +#define __TR_COMMON_H__ + +#include "common.h" +#include "math_common.h" + +#include +#include +#include + +typedef unsigned short triIndex_t; + +// renderCommand_t +enum renderCommand_t +{ + RC_NOP, + RC_DRAW_VIEW_3D, // may be at a reduced resolution, will be upsampled before 2D GUIs + RC_DRAW_VIEW_GUI, // not resolution scaled + RC_SET_BUFFER, + RC_COPY_RENDER, + RC_POST_PROCESS, +}; + +struct emptyCommand_t { + renderCommand_t commandId; + renderCommand_t* next; +}; + + +struct setBufferCommand_t +{ + renderCommand_t commandId; + renderCommand_t* next; + GLenum buffer; +}; + +struct drawSurfsCommand_t { + renderCommand_t commandId; + renderCommand_t* next; + //viewDef_t* viewDef; +}; + +// qqDrawVert +class qqDrawVert +{ +public: + qqVec3 xyz; + halfFloat_t st[2]; + unsigned char normal[4]; + unsigned char tangent[4]; + unsigned char color[4]; + unsigned char color2[4]; +}; + + +#endif // __TR_COMMON_H__ diff --git a/src/miniGLRender/vertexCache.cpp b/src/miniGLRender/vertexCache.cpp new file mode 100644 index 0000000..8fac3b2 --- /dev/null +++ b/src/miniGLRender/vertexCache.cpp @@ -0,0 +1,93 @@ +#include "vertexCache.h" + +/* +============== +ClearGeoBufferSet +============== +*/ +static void ClearGeoBufferSet(geoBufferSet_t& gbs) +{ + gbs.indexMemUsed.SetValue(0); + gbs.vertexMemUsed.SetValue(0); + gbs.jointMemUsed.SetValue(0); + gbs.allocations = 0; +} + +/* +============== +MapGeoBufferSet +============== +*/ +static void MapGeoBufferSet(geoBufferSet_t& gbs) { + if (gbs.mappedVertexBase == NULL) { + gbs.mappedVertexBase = (byte*)gbs.vertexBuffer.MapBuffer(BM_WRITE); + } + if (gbs.mappedIndexBase == NULL) { + gbs.mappedIndexBase = (byte*)gbs.indexBuffer.MapBuffer(BM_WRITE); + } + //if (gbs.mappedJointBase == NULL && gbs.jointBuffer.GetAllocedSize() != 0) { + // gbs.mappedJointBase = (byte*)gbs.jointBuffer.MapBuffer(BM_WRITE); + //} +} + +/* +============== +UnmapGeoBufferSet +============== +*/ +static void UnmapGeoBufferSet(geoBufferSet_t& gbs) { + if (gbs.mappedVertexBase != NULL) { + gbs.vertexBuffer.UnmapBuffer(); + gbs.mappedVertexBase = NULL; + } + if (gbs.mappedIndexBase != NULL) { + gbs.indexBuffer.UnmapBuffer(); + gbs.mappedIndexBase = NULL; + } + //if (gbs.mappedJointBase != NULL) { + // gbs.jointBuffer.UnmapBuffer(); + // gbs.mappedJointBase = NULL; + //} +} + +/* +============== +AllocGeoBufferSet +============== +*/ +static void AllocGeoBufferSet(geoBufferSet_t& gbs, const int vertexBytes, const int indexBytes, const int jointBytes) { + gbs.vertexBuffer.AllocBufferObject(NULL, vertexBytes); + gbs.indexBuffer.AllocBufferObject(NULL, indexBytes); + if (jointBytes != 0) { + // todo + //gbs.jointBuffer.AllocBufferObject(NULL, jointBytes / sizeof(idJointMat)); + } + ClearGeoBufferSet(gbs); +} + +//// qqVertexCache +//void qqVertexCache::Init(bool restart) +//{ +// currentFrame = 0; +// listNum = 0; +// +// mostUsedVertex = 0; +// mostUsedIndex = 0; +// mostUsedJoint = 0; +// +// for (int i = 0; i < VERTCACHE_NUM_FRAMES; i++) { +// AllocGeoBufferSet(frameData[i], VERTCACHE_VERTEX_MEMORY_PER_FRAME, VERTCACHE_INDEX_MEMORY_PER_FRAME, VERTCACHE_JOINT_MEMORY_PER_FRAME); +// } +// AllocGeoBufferSet(staticData, STATIC_VERTEX_MEMORY, STATIC_INDEX_MEMORY, 0); +// +// MapGeoBufferSet(frameData[listNum]); +//} +// +//void qqVertexCache::Shutdown() +//{ +// for (int i = 0; i < VERTCACHE_NUM_FRAMES; i++) { +// frameData[i].vertexBuffer.FreeBufferObject(); +// frameData[i].indexBuffer.FreeBufferObject(); +// frameData[i].jointBuffer.FreeBufferObject(); +// } +//} diff --git a/src/miniGLRender/vertexCache.h b/src/miniGLRender/vertexCache.h new file mode 100644 index 0000000..c0b5bf2 --- /dev/null +++ b/src/miniGLRender/vertexCache.h @@ -0,0 +1,150 @@ +#ifndef __VERTEXCACHE2_H__ +#define __VERTEXCACHE2_H__ + +#include "bufferObjects.h" +#include "thread.h" + +const int VERTCACHE_INDEX_MEMORY_PER_FRAME = 31 * 1024 * 1024; +const int VERTCACHE_VERTEX_MEMORY_PER_FRAME = 31 * 1024 * 1024; +const int VERTCACHE_JOINT_MEMORY_PER_FRAME = 256 * 1024; + +const int VERTCACHE_NUM_FRAMES = 2; + +// there are a lot more static indexes than vertexes, because interactions are just new +// index lists that reference existing vertexes +const int STATIC_INDEX_MEMORY = 31 * 1024 * 1024; +const int STATIC_VERTEX_MEMORY = 31 * 1024 * 1024; // make sure it fits in VERTCACHE_OFFSET_MASK! + +// vertCacheHandle_t packs size, offset, and frame number into 64 bits +typedef uint64 vertCacheHandle_t; +const int VERTCACHE_STATIC = 1; // in the static set, not the per-frame set +const int VERTCACHE_SIZE_SHIFT = 1; +const int VERTCACHE_SIZE_MASK = 0x7fffff; // 8 megs +const int VERTCACHE_OFFSET_SHIFT = 24; +const int VERTCACHE_OFFSET_MASK = 0x1ffffff; // 32 megs +const int VERTCACHE_FRAME_SHIFT = 49; +const int VERTCACHE_FRAME_MASK = 0x7fff; // 15 bits = 32k frames to wrap around + +const int VERTEX_CACHE_ALIGN = 32; +const int INDEX_CACHE_ALIGN = 16; +const int JOINT_CACHE_ALIGN = 16; + +enum cacheType_t +{ + CACHE_VERTEX, + CACHE_INDEX, + CACHE_JOINT +}; + +struct geoBufferSet_t +{ + qqIndexBuffer indexBuffer; + qqVertexBuffer vertexBuffer; + //qqJointBuffer jointBuffer; + + byte* mappedVertexBase; + byte* mappedIndexBase; + byte* mappedJointBase; + + qqSysInterlockedInteger indexMemUsed; + qqSysInterlockedInteger vertexMemUsed; + qqSysInterlockedInteger jointMemUsed; + int allocations; // number of index and vertex allocations combined +}; + +//// qqVertexCache +//class qqVertexCache +//{ +//public: +// void Init(bool restart = false); +// void Shutdown(); +// void PurgeAll(); +// +// // call on loading a new map +// void FreeStaticData(); +// +// // this data is only valid for one frame of rendering +// vertCacheHandle_t AllocVertex(const void* data, int bytes) { +// return ActuallyAlloc(frameData[listNum], data, bytes, CACHE_VERTEX); +// } +// vertCacheHandle_t AllocIndex(const void* data, int bytes) { +// return ActuallyAlloc(frameData[listNum], data, bytes, CACHE_INDEX); +// } +// vertCacheHandle_t AllocJoint(const void* data, int bytes) { +// return ActuallyAlloc(frameData[listNum], data, bytes, CACHE_JOINT); +// } +// +// // this data is valid until the next map load +// vertCacheHandle_t AllocStaticVertex(const void* data, int bytes) { +// if (staticData.vertexMemUsed.GetValue() + bytes > STATIC_VERTEX_MEMORY) { +// idLib::FatalError("AllocStaticVertex failed, increase STATIC_VERTEX_MEMORY"); +// } +// return ActuallyAlloc(staticData, data, bytes, CACHE_VERTEX); +// } +// vertCacheHandle_t AllocStaticIndex(const void* data, int bytes) { +// if (staticData.indexMemUsed.GetValue() + bytes > STATIC_INDEX_MEMORY) { +// idLib::FatalError("AllocStaticIndex failed, increase STATIC_INDEX_MEMORY"); +// } +// return ActuallyAlloc(staticData, data, bytes, CACHE_INDEX); +// } +// +// byte* MappedVertexBuffer(vertCacheHandle_t handle) { +// release_assert(!CacheIsStatic(handle)); +// const uint64 offset = (int)(handle >> VERTCACHE_OFFSET_SHIFT) & VERTCACHE_OFFSET_MASK; +// const uint64 frameNum = (int)(handle >> VERTCACHE_FRAME_SHIFT) & VERTCACHE_FRAME_MASK; +// release_assert(frameNum == (currentFrame & VERTCACHE_FRAME_MASK)); +// return frameData[listNum].mappedVertexBase + offset; +// } +// +// byte* MappedIndexBuffer(vertCacheHandle_t handle) { +// release_assert(!CacheIsStatic(handle)); +// const uint64 offset = (int)(handle >> VERTCACHE_OFFSET_SHIFT) & VERTCACHE_OFFSET_MASK; +// const uint64 frameNum = (int)(handle >> VERTCACHE_FRAME_SHIFT) & VERTCACHE_FRAME_MASK; +// release_assert(frameNum == (currentFrame & VERTCACHE_FRAME_MASK)); +// return frameData[listNum].mappedIndexBase + offset; +// } +// +// // Returns false if it's been purged +// // This can only be called by the front end, the back end should only be looking at +// // vertCacheHandle_t that are already validated. +// bool CacheIsCurrent(const vertCacheHandle_t handle) { +// const int isStatic = handle & VERTCACHE_STATIC; +// if (isStatic) { +// return true; +// } +// const uint64 frameNum = (int)(handle >> VERTCACHE_FRAME_SHIFT) & VERTCACHE_FRAME_MASK; +// if (frameNum != (currentFrame & VERTCACHE_FRAME_MASK)) { +// return false; +// } +// return true; +// } +// +// static bool CacheIsStatic(const vertCacheHandle_t handle) { +// return (handle & VERTCACHE_STATIC) != 0; +// } +// +// // vb/ib is a temporary reference -- don't store it +// bool GetVertexBuffer(vertCacheHandle_t handle, qqVertexBuffer* vb); +// bool GetIndexBuffer(vertCacheHandle_t handle, qqIndexBuffer* ib); +// //bool GetJointBuffer(vertCacheHandle_t handle, idJointBuffer* jb); +// +// void BeginBackEnd(); +// +//public: +// int currentFrame; // for determining the active buffers +// int listNum; // currentFrame % VERTCACHE_NUM_FRAMES +// int drawListNum; // (currentFrame-1) % VERTCACHE_NUM_FRAMES +// +// geoBufferSet_t staticData; +// geoBufferSet_t frameData[VERTCACHE_NUM_FRAMES]; +// +// // High water marks for the per-frame buffers +// int mostUsedVertex; +// int mostUsedIndex; +// int mostUsedJoint; +// +// // Try to make room for bytes +// vertCacheHandle_t ActuallyAlloc(geoBufferSet_t& vcs, const void* data, int bytes, cacheType_t type); +//}; + +#endif