Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
BatchBase.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 //
4 // Copyright (c) 2010-2012 SharpDX - Alexandre Mutel
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 // THE SOFTWARE.
23 
24 using System;
25 using System.Collections.Generic;
26 
27 using SiliconStudio.Core;
28 using SiliconStudio.Paradox.Effects.Modules;
29 using SiliconStudio.Paradox.Graphics.Internals;
30 
31 namespace SiliconStudio.Paradox.Graphics
32 {
33  /// <summary>
34  /// Base class to batch a group of draw calls into one.
35  /// </summary>
36  /// <typeparam name="TDrawInfo">A structure containing all the required information to draw one element of the batch.</typeparam>
37  public abstract class BatchBase<TDrawInfo> : ComponentBase where TDrawInfo : struct
38  {
39  /// <summary>
40  /// The structure containing all the information required to batch one element.
41  /// </summary>
42  protected struct ElementInfo
43  {
44  /// <summary>
45  /// The number of vertex needed to draw the element.
46  /// </summary>
47  public int VertexCount;
48 
49  /// <summary>
50  /// The number of indices needed to draw the element.
51  /// </summary>
52  public int IndexCount;
53 
54  /// <summary>
55  /// The depth of the element. Used to sort the elements.
56  /// </summary>
57  public float Depth;
58 
59  /// <summary>
60  /// The user draw information.
61  /// </summary>
62  public TDrawInfo DrawInfo;
63 
64  public ElementInfo(int vertexCount, int indexCount, ref TDrawInfo drawInfo, float depth = 0)
65  {
66  VertexCount = vertexCount;
67  IndexCount = indexCount;
68  DrawInfo = drawInfo;
69  Depth = depth;
70  }
71  }
72 
73  // TODO: dispose vertex array when Effect is disposed
74  protected readonly DeviceResourceContext ResourceContext;
75 
81  protected int StencilReferenceValue;
83  private EffectParameterResourceBinding? texture0Updater;
84  private EffectParameterResourceBinding? texture1Updater;
85 
86  private int[] sortIndices;
87  private ElementInfo[] sortedDraws;
88  private ElementInfo[] drawsQueue;
89  private int drawsQueueCount;
90  private DrawTextures[] drawTextures;
91 
92  private readonly int vertexStructSize;
93  private readonly int indexStructSize;
94  private readonly VertexDeclaration vertexDeclaration;
95 
96  /// <summary>
97  /// Boolean indicating if we are between a call of Begin and End.
98  /// </summary>
99  private bool isBeginCalled;
100 
101  /// <summary>
102  /// The effect used for the current Begin/End session.
103  /// </summary>
104  protected Effect Effect { get; private set; }
105  protected readonly Effect DefaultEffect;
106 
107  protected TextureIdComparer TextureComparer { get; set; }
108  protected QueueComparer<ElementInfo> BackToFrontComparer { get; set; }
109  protected QueueComparer<ElementInfo> FrontToBackComparer { get; set; }
110 
111  internal const float DepthBiasShiftOneUnit = 0.0001f;
112 
113  protected BatchBase(GraphicsDevice device, Shaders.EffectBytecode defaultEffectByteCode, ResourceBufferInfo resourceBufferInfo, VertexDeclaration vertexDeclaration, int indexSize = sizeof(short))
114  {
115  if (resourceBufferInfo == null) throw new ArgumentNullException("resourceBufferInfo");
116  if (vertexDeclaration == null) throw new ArgumentNullException("vertexDeclaration");
117 
118  GraphicsDevice = device;
119  DefaultEffect = new Effect(device, defaultEffectByteCode) { Name = "BatchDefaultEffect"};
120 
121  drawsQueue = new ElementInfo[resourceBufferInfo.BatchCapacity];
122  drawTextures = new DrawTextures[resourceBufferInfo.BatchCapacity];
123 
124  TextureComparer = new TextureIdComparer();
125  BackToFrontComparer = new SpriteBackToFrontComparer();
126  FrontToBackComparer = new SpriteFrontToBackComparer();
127 
128  // set the vertex layout and size
129  indexStructSize = indexSize;
130  this.vertexDeclaration = vertexDeclaration;
131  vertexStructSize = vertexDeclaration.CalculateSize();
132 
133  // Creates the vertex buffer (shared by within a device context).
134  ResourceContext = GraphicsDevice.GetOrCreateSharedData(GraphicsDeviceSharedDataType.PerContext, resourceBufferInfo.ResourceKey, () => new DeviceResourceContext(GraphicsDevice, DefaultEffect, vertexDeclaration, resourceBufferInfo, indexStructSize));
135  }
136 
137  /// <summary>
138  /// Begins a sprite batch rendering using the specified sorting mode and blend state, sampler, depth stencil, rasterizer state objects and a custom effect.
139  /// Passing null for any of the state objects selects the default default state objects (BlendState.AlphaBlend, depthStencilState.None, RasterizerState.CullCounterClockwise, SamplerState.LinearClamp).
140  /// Passing a null effect selects the default effect shader.
141  /// </summary>
142  /// <param name="effect">The effect to use for this begin/end draw session (default effect if null)</param>
143  /// <param name="sessionSortMode">Sprite drawing order used for the Begin/End session.</param>
144  /// <param name="sessionBlendState">Blending state used for the Begin/End session</param>
145  /// <param name="sessionSamplerState">Texture sampling used for the Begin/End session</param>
146  /// <param name="sessionDepthStencilState">Depth and stencil state used for the Begin/End session</param>
147  /// <param name="sessionRasterizerState">Rasterization state used for the Begin/End session</param>
148  /// <param name="stencilValue">The value of the stencil buffer to take as reference for the Begin/End session</param>
149  protected void Begin(Effect effect, SpriteSortMode sessionSortMode, BlendState sessionBlendState, SamplerState sessionSamplerState, DepthStencilState sessionDepthStencilState, RasterizerState sessionRasterizerState, int stencilValue)
150  {
151  CheckEndHasBeenCalled("begin");
152 
153  SortMode = sessionSortMode;
154  BlendState = sessionBlendState;
155  SamplerState = sessionSamplerState;
156  DepthStencilState = sessionDepthStencilState;
157  RasterizerState = sessionRasterizerState;
158  StencilReferenceValue = stencilValue;
159 
160  Effect = effect ?? DefaultEffect;
161 
162  texture0Updater = null;
163  texture1Updater = null;
165  texture0Updater = Effect.GetParameterFastUpdater(TexturingKeys.Texture0);
167  texture1Updater = Effect.GetParameterFastUpdater(TexturingKeys.Texture1);
168 
169  // Immediate mode, then prepare for rendering here instead of End()
170  if (sessionSortMode == SpriteSortMode.Immediate)
171  {
172  if (ResourceContext.IsInImmediateMode)
173  {
174  throw new InvalidOperationException("Only one SpriteBatch at a time can use SpriteSortMode.Immediate");
175  }
176 
177  PrepareForRendering();
178 
179  ResourceContext.IsInImmediateMode = true;
180  }
181 
182  // Sets to true isBeginCalled
183  isBeginCalled = true;
184  }
185 
186  protected virtual void PrepareForRendering()
187  {
188  // Use LinearClamp for sampler state
189  var localSamplerState = SamplerState ?? GraphicsDevice.SamplerStates.LinearClamp;
190 
191  // Sets the sampler state of the effect
192  Effect.Parameters.Set(TexturingKeys.Sampler, localSamplerState);
193  Effect.Apply();
194 
195  // Setup states (Blend, DepthStencil, Rasterizer)
196  GraphicsDevice.SetBlendState(BlendState ?? GraphicsDevice.BlendStates.AlphaBlend);
197  GraphicsDevice.SetDepthStencilState(DepthStencilState ?? GraphicsDevice.DepthStencilStates.Default, StencilReferenceValue);
198  GraphicsDevice.SetRasterizerState(RasterizerState ?? GraphicsDevice.RasterizerStates.CullBack);
199 
200  // Set VertexInputLayout
201  GraphicsDevice.SetVertexArrayObject(ResourceContext.VertexArrayObject);
202 
203  // If this is a deferred D3D context, reset position so the first Map call will use D3D11_MAP_WRITE_DISCARD.
205  {
206  ResourceContext.VertexBufferPosition = 0;
207  }
208  }
209 
210  protected void CheckBeginHasBeenCalled(string functionName)
211  {
212  if (!isBeginCalled)
213  {
214  throw new InvalidOperationException("Begin must be called before " + functionName);
215  }
216  }
217 
218  protected void CheckEndHasBeenCalled(string functionName)
219  {
220  if (isBeginCalled)
221  {
222  throw new InvalidOperationException("End must be called before " + functionName);
223  }
224  }
225 
226  /// <summary>
227  /// Flushes the sprite batch and restores the device state to how it was before Begin was called.
228  /// </summary>
229  public void End()
230  {
231  CheckBeginHasBeenCalled("End");
232 
233  if (SortMode == SpriteSortMode.Immediate)
234  {
235  ResourceContext.IsInImmediateMode = false;
236  }
237  else if (drawsQueueCount > 0)
238  {
239  // Draw the queued sprites now.
240  if (ResourceContext.IsInImmediateMode)
241  {
242  throw new InvalidOperationException("Cannot end one SpriteBatch while another is using SpriteSortMode.Immediate");
243  }
244 
245  // If not immediate, then setup and render all sprites
246  PrepareForRendering();
247  FlushBatch();
248  }
249 
250  // We are with begin pair
251  isBeginCalled = false;
252  }
253 
254  private void SortSprites()
255  {
256  IComparer<int> comparer;
257 
258  switch (SortMode)
259  {
260  case SpriteSortMode.Texture:
261  TextureComparer.SpriteTextures = drawTextures;
262  comparer = TextureComparer;
263  break;
264 
265  case SpriteSortMode.BackToFront:
266  BackToFrontComparer.ImageInfos = drawsQueue;
267  comparer = BackToFrontComparer;
268  break;
269 
270  case SpriteSortMode.FrontToBack:
271  FrontToBackComparer.ImageInfos = drawsQueue;
272  comparer = FrontToBackComparer;
273  break;
274  default:
275  throw new NotSupportedException();
276  }
277 
278  if ((sortIndices == null) || (sortIndices.Length < drawsQueueCount))
279  {
280  sortIndices = new int[drawsQueueCount];
281  sortedDraws = new ElementInfo[drawsQueueCount];
282  }
283 
284  // Reset all indices to the original order
285  for (int i = 0; i < drawsQueueCount; i++)
286  {
287  sortIndices[i] = i;
288  }
289 
290  Array.Sort(sortIndices, 0, drawsQueueCount, comparer);
291  }
292 
293  private void FlushBatch()
294  {
295  ElementInfo[] spriteQueueForBatch;
296 
297  // If Deferred, then sprites are displayed in the same order they arrived
298  if (SortMode == SpriteSortMode.Deferred)
299  {
300  spriteQueueForBatch = drawsQueue;
301  }
302  else
303  {
304  // Else Sort all sprites according to their sprite order mode.
305  SortSprites();
306  spriteQueueForBatch = sortedDraws;
307  }
308 
309  // Iterate on all sprites and group batch per texture.
310  int offset = 0;
311  var previousTexture = new DrawTextures();
312  for (int i = 0; i < drawsQueueCount; i++)
313  {
314  DrawTextures texture;
315 
316  if (SortMode == SpriteSortMode.Deferred)
317  {
318  texture = drawTextures[i];
319  }
320  else
321  {
322  // Copy ordered sprites to the queue to batch
323  int index = sortIndices[i];
324  spriteQueueForBatch[i] = drawsQueue[index];
325 
326  // Get the texture indirectly
327  texture = drawTextures[index];
328  }
329 
330  if (DrawTextures.NotEqual(ref texture, ref previousTexture))
331  {
332  if (i > offset)
333  {
334  DrawBatchPerTexture(previousTexture.Texture0, previousTexture.Texture1, spriteQueueForBatch, offset, i - offset);
335  }
336 
337  offset = i;
338  previousTexture = texture;
339  }
340  }
341 
342  // Draw the last batch
343  DrawBatchPerTexture(previousTexture.Texture0, previousTexture.Texture1, spriteQueueForBatch, offset, drawsQueueCount - offset);
344 
345  // Reset the queue.
346  Array.Clear(drawTextures, 0, drawsQueueCount);
347  drawsQueueCount = 0;
348 
349  // When sorting is disabled, we persist mSortedSprites data from one batch to the next, to avoid
350  // unnecessary work in GrowSortedSprites. But we never reuse these when sorting, because re-sorting
351  // previously sorted items gives unstable ordering if some sprites have identical sort keys.
352  if (SortMode != SpriteSortMode.Deferred)
353  {
354  Array.Clear(sortedDraws, 0, sortedDraws.Length);
355  }
356  }
357 
358  private void DrawBatchPerTexture(Texture texture, Texture texture1, ElementInfo[] sprites, int offset, int count)
359  {
360  // Sets the texture for this sprite effect.
361  // Use an optimized version in order to avoid to reapply the sprite effect here just to change texture
362  // We are calling directly the PixelShaderStage. We assume that the texture is on slot 0 as it is
363  // setup in the original BasicEffect.fx shader.
364  if (texture0Updater.HasValue)
365  texture0Updater.Value.ApplyParameter(GraphicsDevice, texture);
366  if (texture1Updater.HasValue)
367  texture1Updater.Value.ApplyParameter(GraphicsDevice, texture1);
368 
369  // Draw the batch of sprites
370  DrawBatchPerTextureAndPass(sprites, offset, count);
371  }
372 
373  private void DrawBatchPerTextureAndPass(ElementInfo[] sprites, int offset, int count)
374  {
375  while (count > 0)
376  {
377  // How many index/vertex do we want to draw?
378  var indexCount = 0;
379  var vertexCount = 0;
380  var batchSize = 0;
381 
382  while (batchSize < count)
383  {
384  var spriteIndex = offset + batchSize;
385 
386  // How many sprites does the D3D vertex buffer have room for?
387  var remainingVertexSpace = ResourceContext.VertexCount - ResourceContext.VertexBufferPosition - vertexCount;
388  var remainingIndexSpace = ResourceContext.IndexCount - ResourceContext.IndexBufferPosition - indexCount;
389 
390  // if there is not enough place let for either the indices or vertices of the current element...,
391  if (sprites[spriteIndex].IndexCount > remainingIndexSpace || sprites[spriteIndex].VertexCount > remainingVertexSpace)
392  {
393  // if we haven't started the current batch yet, we restart at the beginning of the buffers.
394  if (batchSize == 0)
395  {
396  ResourceContext.VertexBufferPosition = 0;
397  ResourceContext.IndexBufferPosition = 0;
398  continue;
399  }
400 
401  // else we perform the draw call and batch remaining elements in next draw call.
402  break;
403  }
404 
405  ++batchSize;
406  vertexCount += sprites[spriteIndex].VertexCount;
407  indexCount += sprites[spriteIndex].IndexCount;
408  }
409 
410  // Sets the data directly to the buffer in memory
411  var offsetVertexInBytes = ResourceContext.VertexBufferPosition * vertexStructSize;
412  var offsetIndexInBytes = ResourceContext.IndexBufferPosition * indexStructSize;
413 
414  var noOverwriteVertex = ResourceContext.VertexBufferPosition == 0 ? MapMode.WriteDiscard : MapMode.WriteNoOverwrite;
415  var noOverwriteIndex = ResourceContext.IndexBufferPosition == 0 ? MapMode.WriteDiscard : MapMode.WriteNoOverwrite;
416 
417  // ------------------------------------------------------------------------------------------------------------
418  // CAUTION: Performance problem under x64 resolved by this special codepath:
419  // For some unknown reasons, It seems that writing directly to the pointer returned by the MapSubresource is
420  // extremely inefficient using x64 but using a temporary buffer and performing a mempcy to the locked region
421  // seems to be running at the same speed than x86
422  // ------------------------------------------------------------------------------------------------------------
423  // TODO Check again why we need this code
424  //if (IntPtr.Size == 8)
425  //{
426  // if (x64TempBuffer == null)
427  // {
428  // x64TempBuffer = ToDispose(new DataBuffer(Utilities.SizeOf<VertexPositionColorTexture>() * MaxBatchSize * VerticesPerSprite));
429  // }
430 
431  // // Perform the update of all vertices on a temporary buffer
432  // var texturePtr = (VertexPositionColorTexture*)x64TempBuffer.DataPointer;
433  // for (int i = 0; i < batchSize; i++)
434  // {
435  // UpdateBufferValuesFromElementInfo(ref sprites[offset + i], ref texturePtr, deltaX, deltaY);
436  // }
437 
438  // // Then copy this buffer in one shot
439  // resourceContext.VertexBuffer.SetData(GraphicsDevice, new DataPointer(x64TempBuffer.DataPointer, batchSize * VerticesPerSprite * Utilities.SizeOf<VertexPositionColorTexture>()), offsetInBytes, noOverwrite);
440  //}
441  //else
442  {
443  var mappedIndices = new MappedResource();
444  var mappedVertices = GraphicsDevice.MapSubresource(ResourceContext.VertexBuffer, 0, noOverwriteVertex, false, offsetVertexInBytes, vertexCount * vertexStructSize);
445  if (ResourceContext.IsIndexBufferDynamic)
446  mappedIndices = GraphicsDevice.MapSubresource(ResourceContext.IndexBuffer, 0, noOverwriteIndex, false, offsetIndexInBytes, indexCount * indexStructSize);
447 
448  var vertexPointer = mappedVertices.DataBox.DataPointer;
449  var indexPointer = mappedIndices.DataBox.DataPointer;
450 
451  for (var i = 0; i < batchSize; i++)
452  {
453  var spriteIndex = offset + i;
454 
455  UpdateBufferValuesFromElementInfo(ref sprites[spriteIndex], vertexPointer, indexPointer, ResourceContext.VertexBufferPosition);
456 
457  ResourceContext.VertexBufferPosition += sprites[spriteIndex].VertexCount;
458  vertexPointer += vertexStructSize * sprites[spriteIndex].VertexCount;
459  indexPointer += indexStructSize * sprites[spriteIndex].IndexCount;
460  }
461 
462  GraphicsDevice.UnmapSubresource(mappedVertices);
463  if (ResourceContext.IsIndexBufferDynamic)
464  GraphicsDevice.UnmapSubresource(mappedIndices);
465  }
466 
467  // Draw from the specified index
468  GraphicsDevice.DrawIndexed(PrimitiveType.TriangleList, indexCount, ResourceContext.IndexBufferPosition);
469 
470  // Update position, offset and remaining count
471  ResourceContext.IndexBufferPosition += indexCount;
472  offset += batchSize;
473  count -= batchSize;
474  }
475  }
476 
477  protected void Draw(Texture texture, Texture texture1, ref ElementInfo elementInfo)
478  {
479  // Make sure that Begin was called
480  CheckBeginHasBeenCalled("draw");
481 
482  // Resize the buffer of SpriteInfo
483  if (drawsQueueCount >= drawsQueue.Length)
484  {
485  Array.Resize(ref drawsQueue, drawsQueue.Length * 2);
486  }
487 
488  // set the info required to draw the image
489  drawsQueue[drawsQueueCount] = elementInfo;
490 
491  // If we are in immediate mode, render the sprite directly
492  if (SortMode == SpriteSortMode.Immediate)
493  {
494  DrawBatchPerTexture(texture, texture1, drawsQueue, 0, 1);
495  }
496  else
497  {
498  if (drawTextures.Length < drawsQueue.Length)
499  {
500  Array.Resize(ref drawTextures, drawsQueue.Length);
501  }
502  drawTextures[drawsQueueCount].Texture0 = texture;
503  drawTextures[drawsQueueCount].Texture1 = texture1;
504  drawsQueueCount++;
505  }
506  }
507 
508  /// <summary>
509  /// Update the mapped vertex and index buffer values using the provided element info.
510  /// </summary>
511  /// <param name="elementInfo">The structure containing the information about the element to draw.</param>
512  /// <param name="vertexPointer">The pointer to the vertex array buffer to update.</param>
513  /// <param name="indexPointer">The pointer to the index array buffer to update. This value is null if the index buffer used is static.</param>
514  /// <param name="vexterStartOffset">The offset in the vertex buffer where the vertex of the element starts</param>
515  protected abstract void UpdateBufferValuesFromElementInfo(ref ElementInfo elementInfo, IntPtr vertexPointer, IntPtr indexPointer, int vexterStartOffset);
516 
517  #region Nested types
518 
519  protected struct DrawTextures
520  {
523 
524  public static bool NotEqual(ref DrawTextures left, ref DrawTextures right)
525  {
526  return left.Texture0 != right.Texture0 || left.Texture1 != right.Texture1;
527  }
528  }
529 
530  /// <summary>
531  /// A class containing information on how to build the batch vertex and index buffer.
532  /// </summary>
533  protected class ResourceBufferInfo
534  {
535  /// <summary>
536  /// The key used to identify the GPU resource.
537  /// </summary>
538  public readonly string ResourceKey;
539 
540  /// <summary>
541  /// The initial number of draw calls that can be batched at one time.
542  /// </summary>
543  /// <remarks>Data structure will adjust their size when needed if capacity is not sufficient</remarks>
544  public int BatchCapacity { get; set; }
545 
546  /// <summary>
547  /// Gets the number indices of the vertex buffer.
548  /// </summary>
549  public int VertexCount { get; protected set; }
550 
551  /// <summary>
552  /// Gets the number indices of the index buffer.
553  /// </summary>
554  public int IndexCount { get; private set; }
555 
556  /// <summary>
557  /// Gets or sets the static indices to use for the index buffer.
558  /// </summary>
559  public short[] StaticIndices;
560 
561  /// <summary>
562  /// Gets the value indicating whether the index buffer is static or dynamic.
563  /// </summary>
564  public bool IsIndexBufferDynamic { get { return StaticIndices == null; } }
565 
566  /// <summary>
567  /// Create the buffer resource information for a batch having both a dynamic index buffer and vertex buffer.
568  /// </summary>
569  /// <param name="resourceKey">The name of key to use to identify the resource</param>
570  /// <param name="indexCount">The number of indices contained by the index buffer</param>
571  /// <param name="vertexCount">The number of vertices contained by the vertex buffer</param>
572  public static ResourceBufferInfo CreateDynamicIndexBufferInfo(string resourceKey, int indexCount, int vertexCount)
573  {
574  return new ResourceBufferInfo(resourceKey, null, indexCount, vertexCount);
575  }
576 
577  /// <summary>
578  /// Create the buffer resource information for a batch having a dynamic vertex buffer but a static index buffer.
579  /// </summary>
580  /// <param name="resourceKey">The name of key to use to identify the resource</param>
581  /// <param name="staticIndices">The value of the indices to upload into the index buffer.</param>
582  /// <param name="vertexCount">The number of vertices contained by the vertex buffer</param>
583  public static ResourceBufferInfo CreateStaticIndexBufferInfo(string resourceKey, short[] staticIndices, int vertexCount)
584  {
585  return new ResourceBufferInfo(resourceKey, staticIndices, 0, vertexCount);
586  }
587 
588  protected ResourceBufferInfo(string resourceKey, short[] staticIndices, int indexCount, int vertexCount)
589  {
590  if (staticIndices != null)
591  indexCount = staticIndices.Length;
592 
593  BatchCapacity = 64;
594  ResourceKey = resourceKey;
595  StaticIndices = staticIndices;
596  IndexCount = indexCount;
597  VertexCount = vertexCount;
598  }
599  }
600  /// <summary>
601  /// A class containing the information required to build a vertex and index buffer for simple quad based batching.
602  /// </summary>
603  /// <remarks>
604  /// The index buffer is used in static mode and contains six indices for each quad. The vertex buffer contains 4 vertices for each quad.
605  /// Rectangle is composed of two triangles as follow:
606  /// v0 - - - v1
607  /// | \ |
608  /// | \ t1 |
609  /// | t2 \ |
610  /// v3 - - - v2
611  /// </remarks>
612  protected class StaticQuadBufferInfo: ResourceBufferInfo
613  {
614  public const int IndicesByElement = 6;
615 
616  public const int VertexByElement = 4;
617 
618  private StaticQuadBufferInfo(string resourceKey, short[] staticIndices, int vertexCount)
619  : base(resourceKey, staticIndices, 0, vertexCount)
620  {
621  }
622 
623  public static StaticQuadBufferInfo CreateQuadBufferInfo(string resourceKey, int maxQuadNumber, int batchCapacity = 64)
624  {
625  var indices = new short[maxQuadNumber * IndicesByElement];
626  var k = 0;
627  for (var i = 0; i < indices.Length; k += VertexByElement)
628  {
629  indices[i++] = (short)(k + 0);
630  indices[i++] = (short)(k + 1);
631  indices[i++] = (short)(k + 2);
632  indices[i++] = (short)(k + 0);
633  indices[i++] = (short)(k + 2);
634  indices[i++] = (short)(k + 3);
635  }
636 
637  return new StaticQuadBufferInfo(resourceKey, indices, VertexByElement * maxQuadNumber) { BatchCapacity = batchCapacity };
638  }
639  }
640 
641  protected class TextureIdComparer : IComparer<int>
642  {
643  public DrawTextures[] SpriteTextures;
644 
645  public int Compare(int left, int right)
646  {
647  return SpriteTextures[left].Texture0.Id.CompareTo(SpriteTextures[right].Texture0.Id);
648  }
649  }
650 
651  private class SpriteBackToFrontComparer : QueueComparer<ElementInfo>
652  {
653  public override int Compare(int left, int right)
654  {
655  return ImageInfos[left].Depth.CompareTo(ImageInfos[right].Depth);
656  }
657  }
658 
659  private class SpriteFrontToBackComparer : QueueComparer<ElementInfo>
660  {
661  public override int Compare(int left, int right)
662  {
663  return ImageInfos[right].Depth.CompareTo(ImageInfos[left].Depth);
664  }
665  }
666 
667  protected abstract class QueueComparer<TInfo> : IComparer<int>
668  {
669  public TInfo[] ImageInfos;
670 
671  public abstract int Compare(int x, int y);
672  }
673 
674  /// <summary>
675  /// Use a ResourceContext per GraphicsDevice (DeviceContext)
676  /// </summary>
677  protected class DeviceResourceContext : ComponentBase
678  {
679  /// <summary>
680  /// Gets the number of vertices.
681  /// </summary>
682  public readonly int VertexCount;
683 
684  /// <summary>
685  /// The vertex buffer of the batch.
686  /// </summary>
687  public readonly Buffer VertexBuffer;
688 
689  /// <summary>
690  /// Gets the number of indices.
691  /// </summary>
692  public readonly int IndexCount;
693 
694  /// <summary>
695  /// The index buffer of the batch.
696  /// </summary>
697  public readonly Buffer IndexBuffer;
698 
699  /// <summary>
700  /// Gets a boolean indicating if the index buffer is dynamic.
701  /// </summary>
702  public readonly bool IsIndexBufferDynamic;
703 
704  /// <summary>
705  /// The VertexArrayObject of the batch.
706  /// </summary>
708 
709  /// <summary>
710  /// The current position in vertex into the vertex array buffer.
711  /// </summary>
713 
714  /// <summary>
715  /// The current position in index into the index array buffer.
716  /// </summary>
718 
719  /// <summary>
720  /// Indicate if the batch system is drawing in immediate mode for this buffer.
721  /// </summary>
722  public bool IsInImmediateMode;
723 
724  public DeviceResourceContext(GraphicsDevice device, Effect effect, VertexDeclaration declaration, ResourceBufferInfo resourceBufferInfo, int indexStructSize)
725  {
726  var vertexSize = declaration.CalculateSize();
727 
728  VertexCount = resourceBufferInfo.VertexCount;
729  IndexCount = resourceBufferInfo.IndexCount;
730  IsIndexBufferDynamic = resourceBufferInfo.IsIndexBufferDynamic;
731 
732  VertexBuffer = Buffer.Vertex.New(device, VertexCount * vertexSize, GraphicsResourceUsage.Dynamic).DisposeBy(this);
733 
734  if (IsIndexBufferDynamic)
735  {
736  IndexBuffer = Buffer.Index.New(device, IndexCount * indexStructSize, GraphicsResourceUsage.Dynamic).DisposeBy(this);
737  }
738  else
739  {
740  IndexBuffer = Buffer.Index.New(device, resourceBufferInfo.StaticIndices).DisposeBy(this);
741  IndexBuffer.Reload = graphicsResource => ((Buffer)graphicsResource).Recreate(resourceBufferInfo.StaticIndices);
742  }
743 
744  var indexBufferBinding = new IndexBufferBinding(IndexBuffer, indexStructSize == sizeof(int), IndexBuffer.Description.SizeInBytes / indexStructSize);
745  var vertexBufferBinding = new VertexBufferBinding(VertexBuffer, declaration, VertexCount, vertexSize);
746 
747  // Creates a VAO
748  VertexArrayObject = VertexArrayObject.New(device, effect.InputSignature, indexBufferBinding, vertexBufferBinding).DisposeBy(this);
749  }
750  }
751 
752  #endregion
753  }
754 }
int IndexCount
The number of indices needed to draw the element.
Definition: BatchBase.cs:52
The layout of a vertex buffer with a set of VertexElement.
int IndexBufferPosition
The current position in index into the index array buffer.
Definition: BatchBase.cs:717
static readonly ParameterKey< Texture > Texture1
Definition: Texturing.cs:23
void End()
Flushes the sprite batch and restores the device state to how it was before Begin was called...
Definition: BatchBase.cs:229
Contains depth-stencil state for the device.
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
Definition: DirectXTexP.h:191
ElementInfo(int vertexCount, int indexCount, ref TDrawInfo drawInfo, float depth=0)
Definition: BatchBase.cs:64
Base class for a framework component.
All-in-One Buffer class linked SharpDX.Direct3D11.Buffer.
SiliconStudio.Paradox.Graphics.Buffer Buffer
Definition: BasicEffect.cs:15
Performs primitive-based rendering, creates resources, handles system-level variables, adjusts gamma ramp levels, and creates shaders. See The+GraphicsDevice+class to learn more about the class.
_In_ size_t count
Definition: DirectXTexP.h:174
bool HasParameter(ParameterKey parameterKey)
Definition: Effect.cs:309
SpriteSortMode
Defines sprite sort-rendering options.
readonly Buffer IndexBuffer
The index buffer of the batch.
Definition: BatchBase.cs:697
ResourceBufferInfo(string resourceKey, short[] staticIndices, int indexCount, int vertexCount)
Definition: BatchBase.cs:588
readonly VertexArrayObject VertexArrayObject
The VertexArrayObject of the batch.
Definition: BatchBase.cs:707
BatchBase(GraphicsDevice device, Shaders.EffectBytecode defaultEffectByteCode, ResourceBufferInfo resourceBufferInfo, VertexDeclaration vertexDeclaration, int indexSize=sizeof(short))
Definition: BatchBase.cs:113
void Begin(Effect effect, SpriteSortMode sessionSortMode, BlendState sessionBlendState, SamplerState sessionSamplerState, DepthStencilState sessionDepthStencilState, RasterizerState sessionRasterizerState, int stencilValue)
Begins a sprite batch rendering using the specified sorting mode and blend state, sampler...
Definition: BatchBase.cs:149
static ResourceBufferInfo CreateStaticIndexBufferInfo(string resourceKey, short[] staticIndices, int vertexCount)
Create the buffer resource information for a batch having a dynamic vertex buffer but a static index ...
Definition: BatchBase.cs:583
static StaticQuadBufferInfo CreateQuadBufferInfo(string resourceKey, int maxQuadNumber, int batchCapacity=64)
Definition: BatchBase.cs:623
float Depth
The depth of the element. Used to sort the elements.
Definition: BatchBase.cs:57
bool IsDeferred
Gets a value indicating whether this instance is a deferred graphics device context.
int VertexBufferPosition
The current position in vertex into the vertex array buffer.
Definition: BatchBase.cs:712
static readonly ParameterKey< Texture > Texture0
Definition: Texturing.cs:21
readonly DeviceResourceContext ResourceContext
Definition: BatchBase.cs:74
readonly Buffer VertexBuffer
The vertex buffer of the batch.
Definition: BatchBase.cs:687
short[] StaticIndices
Gets or sets the static indices to use for the index buffer.
Definition: BatchBase.cs:559
void Draw(Texture texture, Texture texture1, ref ElementInfo elementInfo)
Definition: BatchBase.cs:477
static ResourceBufferInfo CreateDynamicIndexBufferInfo(string resourceKey, int indexCount, int vertexCount)
Create the buffer resource information for a batch having both a dynamic index buffer and vertex buff...
Definition: BatchBase.cs:572
bool IsInImmediateMode
Indicate if the batch system is drawing in immediate mode for this buffer.
Definition: BatchBase.cs:722
static bool NotEqual(ref DrawTextures left, ref DrawTextures right)
Definition: BatchBase.cs:524
readonly bool IsIndexBufferDynamic
Gets a boolean indicating if the index buffer is dynamic.
Definition: BatchBase.cs:702
DeviceResourceContext(GraphicsDevice device, Effect effect, VertexDeclaration declaration, ResourceBufferInfo resourceBufferInfo, int indexStructSize)
Definition: BatchBase.cs:724
readonly string ResourceKey
The key used to identify the GPU resource.
Definition: BatchBase.cs:538
Base class for texture resources.
Definition: Texture.cs:38
Binding structure that specifies a vertex buffer and other per-vertex parameters (such as offset and ...
int VertexCount
The number of vertex needed to draw the element.
Definition: BatchBase.cs:47