Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

358 lines
11 KiB

  1. //============ Copyright (c) Valve Corporation, All rights reserved. ============
  2. //
  3. // cglmbuffer.cpp
  4. //
  5. //===============================================================================
  6. #include "glmgr/glmgr.h"
  7. #include "glmgr/cglmbuffer.h"
  8. // memdbgon -must- be the last include file in a .cpp file.
  9. #include "tier0/memdbgon.h"
  10. // void BindBufferARB(enum target, uint buffer);
  11. // void DeleteBuffersARB(sizei n, const uint *buffers);
  12. // void GenBuffersARB(sizei n, uint *buffers);
  13. // boolean IsBufferARB(uint buffer);
  14. //
  15. // void BufferDataARB(enum target, sizeiptrARB size, const void *data,
  16. // enum usage);
  17. // void BufferSubDataARB(enum target, intptrARB offset, sizeiptrARB size,
  18. // const void *data);
  19. // void GetBufferSubDataARB(enum target, intptrARB offset,
  20. // sizeiptrARB size, void *data);
  21. //
  22. // void *MapBufferARB(enum target, enum access);
  23. // boolean UnmapBufferARB(enum target);
  24. //
  25. // void GetBufferParameterivARB(enum target, enum pname, int *params);
  26. // void GetBufferPointervARB(enum target, enum pname, void **params);
  27. //
  28. //New Tokens
  29. //
  30. // Accepted by the <target> parameters of BindBufferARB, BufferDataARB,
  31. // BufferSubDataARB, MapBufferARB, UnmapBufferARB,
  32. // GetBufferSubDataARB, GetBufferParameterivARB, and
  33. // GetBufferPointervARB:
  34. //
  35. // ARRAY_BUFFER_ARB 0x8892
  36. // ELEMENT_ARRAY_BUFFER_ARB 0x8893
  37. //
  38. // Accepted by the <pname> parameter of GetBooleanv, GetIntegerv,
  39. // GetFloatv, and GetDoublev:
  40. //
  41. // ARRAY_BUFFER_BINDING_ARB 0x8894
  42. // ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
  43. // VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
  44. // NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
  45. // COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
  46. // INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
  47. // TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
  48. // EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
  49. // SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
  50. // FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
  51. // WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
  52. //
  53. // Accepted by the <pname> parameter of GetVertexAttribivARB:
  54. //
  55. // VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
  56. //
  57. // Accepted by the <usage> parameter of BufferDataARB:
  58. //
  59. // STREAM_DRAW_ARB 0x88E0
  60. // STREAM_READ_ARB 0x88E1
  61. // STREAM_COPY_ARB 0x88E2
  62. // STATIC_DRAW_ARB 0x88E4
  63. // STATIC_READ_ARB 0x88E5
  64. // STATIC_COPY_ARB 0x88E6
  65. // DYNAMIC_DRAW_ARB 0x88E8
  66. // DYNAMIC_READ_ARB 0x88E9
  67. // DYNAMIC_COPY_ARB 0x88EA
  68. //
  69. // Accepted by the <access> parameter of MapBufferARB:
  70. //
  71. // READ_ONLY_ARB 0x88B8
  72. // WRITE_ONLY_ARB 0x88B9
  73. // READ_WRITE_ARB 0x88BA
  74. //
  75. // Accepted by the <pname> parameter of GetBufferParameterivARB:
  76. //
  77. // BUFFER_SIZE_ARB 0x8764
  78. // BUFFER_USAGE_ARB 0x8765
  79. // BUFFER_ACCESS_ARB 0x88BB
  80. // BUFFER_MAPPED_ARB 0x88BC
  81. //
  82. // Accepted by the <pname> parameter of GetBufferPointervARB:
  83. //
  84. // BUFFER_MAP_POINTER_ARB 0x88BD
  85. // http://www.opengl.org/registry/specs/ARB/pixel_buffer_object.txt
  86. // Accepted by the <target> parameters of BindBuffer, BufferData,
  87. // BufferSubData, MapBuffer, UnmapBuffer, GetBufferSubData,
  88. // GetBufferParameteriv, and GetBufferPointerv:
  89. // PIXEL_PACK_BUFFER_ARB 0x88EB
  90. // PIXEL_UNPACK_BUFFER_ARB 0x88EC
  91. // gl_bufmode: zero means we mark all vertex/index buffers static
  92. // non zero means buffers are initially marked static..
  93. // ->but can shift to dynamic upon first 'discard' (orphaning)
  94. ConVar gl_bufmode( "gl_bufmode", "1" );
  95. CGLMBuffer::CGLMBuffer( GLMContext *ctx, EGLMBufferType type, uint size, uint options )
  96. {
  97. m_ctx = ctx;
  98. m_type = type;
  99. switch(m_type)
  100. {
  101. case kGLMVertexBuffer: m_buffGLTarget = GL_ARRAY_BUFFER_ARB; break;
  102. case kGLMIndexBuffer: m_buffGLTarget = GL_ELEMENT_ARRAY_BUFFER_ARB; break;
  103. case kGLMUniformBuffer: m_buffGLTarget = GL_UNIFORM_BUFFER_EXT; break;
  104. case kGLMPixelBuffer: m_buffGLTarget = GL_PIXEL_UNPACK_BUFFER_ARB; break;
  105. default: Assert(!"Unknown buffer type" );
  106. }
  107. m_size = size;
  108. m_bound = false;
  109. m_mapped = false;
  110. m_lastMappedAddress = NULL;
  111. m_enableAsyncMap = false;
  112. m_enableExplicitFlush = false;
  113. m_dirtyMinOffset = m_dirtyMaxOffset = 0; // adjust/grow on lock, clear on unlock
  114. m_ctx->CheckCurrent();
  115. m_revision = rand();
  116. // make a decision about pseudo mode
  117. // this looked like it didn't help much or was actually slower, so leave it available but only as opt-in.
  118. // a more clever implementation would be able to select pseudo buf storage for small batches only..
  119. m_pseudo = (m_type==kGLMIndexBuffer) && (CommandLine()->FindParm("-gl_enable_pseudobufs"));
  120. if (m_pseudo)
  121. {
  122. m_name = 0;
  123. m_pseudoBuf = (char*)malloc( size );
  124. m_ctx->BindBufferToCtx( m_type, NULL ); // exit with no buffer bound
  125. }
  126. else
  127. {
  128. glGenBuffersARB( 1, &m_name );
  129. GLMCheckError();
  130. m_ctx->BindBufferToCtx( m_type, this ); // causes glBindBufferARB
  131. // buffers start out static, but if they get orphaned and gl_bufmode is non zero,
  132. // then they will get flipped to dynamic.
  133. GLenum hint = GL_STATIC_DRAW_ARB;
  134. switch(m_type)
  135. {
  136. case kGLMVertexBuffer: hint = (options & GLMBufferOptionDynamic) ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB; break;
  137. case kGLMIndexBuffer: hint = (options & GLMBufferOptionDynamic) ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB; break;
  138. case kGLMUniformBuffer: hint = GL_DYNAMIC_DRAW_ARB; break; // "fwiw" - shrug
  139. case kGLMPixelBuffer: hint = (options & GLMBufferOptionDynamic) ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB; break;
  140. default: Assert(!"Unknown buffer type" );
  141. }
  142. glBufferDataARB( m_buffGLTarget, m_size, NULL, hint ); // may ultimately need more hints to set the usage correctly (esp for streaming)
  143. this->SetModes( true, true, true );
  144. m_ctx->BindBufferToCtx( m_type, NULL ); // unbind me
  145. }
  146. }
  147. CGLMBuffer::~CGLMBuffer( )
  148. {
  149. m_ctx->CheckCurrent();
  150. if (m_pseudo)
  151. {
  152. free (m_pseudoBuf);
  153. m_pseudoBuf = NULL;
  154. }
  155. else
  156. {
  157. glDeleteBuffersARB( 1, &m_name );
  158. GLMCheckError();
  159. }
  160. m_ctx = NULL;
  161. m_name = 0;
  162. m_bound = 0;
  163. m_lastMappedAddress = NULL;
  164. }
  165. void CGLMBuffer::SetModes ( bool asyncMap, bool explicitFlush, bool force )
  166. {
  167. // assumes buffer is bound. called by constructor and by Lock.
  168. if (m_pseudo)
  169. {
  170. // ignore it...
  171. }
  172. else
  173. {
  174. if (force || (m_enableAsyncMap != asyncMap) )
  175. {
  176. // note the sense of the parameter, it's TRUE if you *want* serialization, so for async you turn it to false.
  177. glBufferParameteriAPPLE( this->m_buffGLTarget, GL_BUFFER_SERIALIZED_MODIFY_APPLE, asyncMap==false );
  178. m_enableAsyncMap = asyncMap;
  179. }
  180. if (force || (m_enableExplicitFlush != explicitFlush) )
  181. {
  182. // note the sense of the parameter, it's TRUE if you *want* auto-flush-on-unmap, so for explicit-flush, you turn it to false.
  183. glBufferParameteriAPPLE( this->m_buffGLTarget, GL_BUFFER_FLUSHING_UNMAP_APPLE, explicitFlush==false );
  184. m_enableExplicitFlush = explicitFlush;
  185. }
  186. }
  187. }
  188. void CGLMBuffer::FlushRange ( uint offset, uint size )
  189. {
  190. if (m_pseudo)
  191. {
  192. // nothing to do
  193. }
  194. else
  195. {
  196. // assumes buffer is bound.
  197. glFlushMappedBufferRangeAPPLE(this->m_buffGLTarget, (GLintptr)offset, (GLsizeiptr)size);
  198. }
  199. }
  200. ConVar gl_buffer_alignment_quantum ( "gl_buffer_alignment_quantum", "32" ); // the alignment we use pre-SLGU
  201. ConVar gl_buffer_alignment_quantum_slgu( "gl_buffer_alignment_quantum_slgu", "2" ); // alignment used post-SLGU
  202. void CGLMBuffer::Lock( GLMBuffLockParams *params, char **addressOut )
  203. {
  204. char *resultPtr = NULL;
  205. Assert( !m_mapped);
  206. m_ctx->CheckCurrent();
  207. GLMCheckError();
  208. if (params->m_offset >= m_size)
  209. Debugger();
  210. if (params->m_offset + params->m_size > m_size)
  211. Debugger();
  212. // bind (yes, even for pseudo - this binds name 0)
  213. m_ctx->BindBufferToCtx( this->m_type, this );
  214. if (m_pseudo)
  215. {
  216. // discard is a no-op
  217. // async map modes are a no-op
  218. // latch last mapped address (silly..)
  219. m_lastMappedAddress = (float*)m_pseudoBuf;
  220. // calc lock address
  221. resultPtr = m_pseudoBuf + params->m_offset;
  222. // dirty range is a no-op
  223. }
  224. else
  225. {
  226. // perform discard if requested
  227. if (params->m_discard)
  228. {
  229. // observe gl_bufmode on any orphan event.
  230. // if orphaned and bufmode is nonzero, flip it to dynamic.
  231. GLenum hint = gl_bufmode.GetInt() ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB;
  232. glBufferDataARB( m_buffGLTarget, m_size, NULL, hint );
  233. m_lastMappedAddress = NULL;
  234. m_revision++; // revision grows on orphan event
  235. }
  236. // adjust async map option appropriately, leave explicit flush unchanged
  237. this->SetModes( params->m_nonblocking, m_enableExplicitFlush );
  238. // map
  239. char *mapPtr = (char*)glMapBufferARB( this->m_buffGLTarget, GL_READ_WRITE_ARB );
  240. if (!mapPtr)
  241. {
  242. Debugger();
  243. }
  244. if (m_lastMappedAddress)
  245. {
  246. // just check if it moved
  247. Assert (m_lastMappedAddress == (float*)mapPtr);
  248. }
  249. m_lastMappedAddress = (float*)mapPtr;
  250. // calculate offset location
  251. resultPtr = mapPtr + params->m_offset;
  252. // adjust dirty range
  253. if (m_dirtyMinOffset != m_dirtyMaxOffset)
  254. {
  255. // grow range
  256. m_dirtyMinOffset = MIN( m_dirtyMinOffset, params->m_offset );
  257. m_dirtyMaxOffset = MIN( m_dirtyMaxOffset, params->m_offset+params->m_size );
  258. }
  259. else
  260. {
  261. // set range
  262. m_dirtyMinOffset = params->m_offset;
  263. m_dirtyMaxOffset = params->m_offset+params->m_size;
  264. }
  265. // pad and clamp dirty range to choice of boundary
  266. uint quantum = (m_ctx->Caps().m_hasPerfPackage1) ? gl_buffer_alignment_quantum_slgu.GetInt() : gl_buffer_alignment_quantum.GetInt();
  267. uint quantum_mask = quantum - 1;
  268. m_dirtyMinOffset = m_dirtyMinOffset & (~quantum_mask);
  269. m_dirtyMaxOffset = (m_dirtyMaxOffset + quantum_mask) & (~quantum_mask);
  270. m_dirtyMaxOffset = MIN( m_dirtyMaxOffset, m_size );
  271. }
  272. m_mapped = true;
  273. *addressOut = resultPtr;
  274. }
  275. void CGLMBuffer::Unlock( void )
  276. {
  277. m_ctx->CheckCurrent();
  278. Assert (m_mapped);
  279. if (m_pseudo)
  280. {
  281. // nothing to do actually
  282. }
  283. else
  284. {
  285. m_ctx->BindBufferToCtx( this->m_type, this );
  286. // time to do explicit flush
  287. if (m_enableExplicitFlush)
  288. {
  289. this->FlushRange( m_dirtyMinOffset, m_dirtyMaxOffset - m_dirtyMinOffset );
  290. }
  291. // clear dirty range no matter what
  292. m_dirtyMinOffset = m_dirtyMaxOffset = 0; // adjust/grow on lock, clear on unlock
  293. glUnmapBuffer( this->m_buffGLTarget );
  294. }
  295. m_mapped = false;
  296. }