This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

269 lines
7.9 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// cglmprogram.h
// GLMgr buffers (index / vertex)
// ... maybe add PBO later as well
//===============================================================================
#ifndef CGLMBUFFER_H
#define CGLMBUFFER_H
#pragma once
//===============================================================================
extern bool g_bUsePseudoBufs;
// forward declarations
class GLMContext;
enum EGLMBufferType {
kGLMVertexBuffer,
kGLMIndexBuffer,
kGLMUniformBuffer, // for bindable uniform
kGLMPixelBuffer, // for PBO
kGLMNumBufferTypes
};
// pass this in "options" to constructor to make a dynamic buffer
#define GLMBufferOptionDynamic 0x00000001
struct GLMBuffLockParams {
uint m_nOffset;
uint m_nSize;
bool m_bNoOverwrite;
bool m_bDiscard;
};
#define GL_STATIC_BUFFER_SIZE (2048 * 1024)
#define GL_MAX_STATIC_BUFFERS 2
extern void glBufferSubDataMaxSize(GLenum target, GLintptr offset,
GLsizeiptr size, const GLvoid *data,
uint nMaxSizePerCall = 128 * 1024);
//===========================================================================//
// Creates an immutable storage for a buffer object
// https://www.opengl.org/registry/specs/ARB/buffer_storage.txt
class CPersistentBuffer {
public:
CPersistentBuffer();
~CPersistentBuffer();
void Init(EGLMBufferType type, uint nSize);
void Deinit();
void InsertFence();
void BlockUntilNotBusy();
void Append(uint nSize);
inline uint GetBytesRemaining() const { return m_nSize - m_nOffset; }
inline uint GetOffset() const { return m_nOffset; }
inline void *GetPtr() const { return m_pImmutablePersistentBuf; }
inline GLuint GetHandle() const { return m_nHandle; }
private:
CPersistentBuffer(const CPersistentBuffer &);
CPersistentBuffer &operator=(const CPersistentBuffer &);
uint m_nSize;
EGLMBufferType m_type;
GLenum m_buffGLTarget; // GL_ARRAY_BUFFER_ARB / GL_ELEMENT_BUFFER_ARB
GLuint m_nHandle; // handle of this program in the GL context
// Holds a pointer to the persistently mapped buffer
void *m_pImmutablePersistentBuf;
uint m_nOffset;
#ifdef HAVE_GL_ARB_SYNC
GLsync m_nSyncObj;
#endif
};
//===============================================================================
#if GL_ENABLE_INDEX_VERIFICATION
struct GLDynamicBuf_t {
GLenum m_nGLType;
uint m_nHandle;
uint m_nActualBufSize;
uint m_nSize;
uint m_nLockOffset;
uint m_nLockSize;
};
class CGLMBufferSpanManager {
CGLMBufferSpanManager(const CGLMBufferSpanManager &);
CGLMBufferSpanManager &operator=(const CGLMBufferSpanManager &);
public:
CGLMBufferSpanManager();
~CGLMBufferSpanManager();
void Init(GLMContext *pContext, EGLMBufferType nBufType,
uint nInitialCapacity, uint nBufSize, bool bDynamic);
void Deinit();
inline GLMContext *GetContext() const { return m_pCtx; }
inline GLenum GetGLBufType() const {
return (m_nBufType == kGLMVertexBuffer) ? GL_ARRAY_BUFFER_ARB
: GL_ELEMENT_ARRAY_BUFFER_ARB;
}
struct ActiveSpan_t {
uint m_nStart;
uint m_nEnd;
GLDynamicBuf_t m_buf;
bool m_bOriginalAlloc;
inline ActiveSpan_t() {}
inline ActiveSpan_t(uint nStart, uint nEnd, GLDynamicBuf_t &buf,
bool bOriginalAlloc)
: m_nStart(nStart),
m_nEnd(nEnd),
m_buf(buf),
m_bOriginalAlloc(bOriginalAlloc) {
Assert(nStart <= nEnd);
}
};
ActiveSpan_t *AddSpan(uint nOffset, uint nMaxSize, uint nActualSize,
bool bDiscard, bool bNoOverwrite);
void DiscardAllSpans();
bool IsValid(uint nOffset, uint nSize) const;
private:
bool AllocDynamicBuf(uint nSize, GLDynamicBuf_t &buf);
void ReleaseDynamicBuf(GLDynamicBuf_t &buf);
GLMContext *m_pCtx;
EGLMBufferType m_nBufType;
uint m_nBufSize;
bool m_bDynamic;
CUtlVector<ActiveSpan_t> m_ActiveSpans;
CUtlVector<ActiveSpan_t> m_DeletedSpans;
int m_nSpanEndMax;
int m_nNumAllocatedBufs;
int m_nTotalBytesAllocated;
};
#endif // GL_ENABLE_INDEX_VERIFICATION
class CGLMBuffer {
public:
void Lock(GLMBuffLockParams *pParams, char **pAddressOut);
void Unlock(int nActualSize = -1, const void *pActualData = NULL);
GLuint GetHandle() const;
friend class GLMContext; // only GLMContext can make CGLMBuffer objects
friend class GLMTester;
friend struct IDirect3D9;
friend struct IDirect3DDevice9;
CGLMBuffer(GLMContext *pCtx, EGLMBufferType type, uint size, uint options);
~CGLMBuffer();
void SetModes(bool bAsyncMap, bool bExplicitFlush, bool bForce = false);
void FlushRange(uint offset, uint size);
#if GL_ENABLE_INDEX_VERIFICATION
bool IsSpanValid(uint nOffset, uint nSize) const;
#endif
GLMContext *m_pCtx; // link back to parent context
EGLMBufferType m_type;
uint m_nSize;
uint m_nActualSize;
bool m_bDynamic;
GLenum m_buffGLTarget; // GL_ARRAY_BUFFER_ARB / GL_ELEMENT_BUFFER_ARB
GLuint m_nHandle; // name of this program in the context
uint m_nRevision; // bump anytime the size changes or buffer is orphaned
bool m_bEnableAsyncMap; // mirror of the buffer state
bool m_bEnableExplicitFlush; // mirror of the buffer state
bool m_bMapped; // is it currently mapped
uint m_dirtyMinOffset; // when equal, range is empty
uint m_dirtyMaxOffset;
float *m_pLastMappedAddress;
int m_nPinnedMemoryOfs;
uint m_nPersistentBufferStartOffset;
bool m_bUsingPersistentBuffer;
bool m_bPseudo; // true if the m_name is 0, and the backing is plain RAM
// in pseudo mode, there is just one RAM buffer that acts as the backing.
// expectation is that this mode would only be used for dynamic indices.
// since indices have to be consumed (copied to command stream) prior to
// return from a drawing call, there's no need to do any fencing or
// multibuffering. orphaning in particular becomes a no-op.
char *m_pActualPseudoBuf; // storage for pseudo buffer
char *m_pPseudoBuf; // storage for pseudo buffer
char *m_pStaticBuffer;
GLMBuffLockParams m_LockParams;
static char ALIGN16 m_StaticBuffers[GL_MAX_STATIC_BUFFERS]
[GL_STATIC_BUFFER_SIZE] ALIGN16_POST;
static bool m_bStaticBufferUsed[GL_MAX_STATIC_BUFFERS];
#if GL_ENABLE_INDEX_VERIFICATION
CGLMBufferSpanManager m_BufferSpanManager;
#endif
#if GL_ENABLE_UNLOCK_BUFFER_OVERWRITE_DETECTION
uint m_nDirtyRangeStart;
uint m_nDirtyRangeEnd;
#endif
};
#endif // CGLMBUFFER_H