Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
GraphicsDevice.OpenGL.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 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGL
4 #if SILICONSTUDIO_PLATFORM_ANDROID
5 extern alias opentkold;
6 #endif
7 using System;
8 using System.Collections.Generic;
9 using System.Linq;
10 using System.Threading;
11 using OpenTK.Graphics;
12 using OpenTK.Platform;
13 using SiliconStudio.Core;
14 using SiliconStudio.Core.Mathematics;
15 using SiliconStudio.Paradox.Effects.Modules;
16 using SiliconStudio.Paradox.Shaders;
18 #if SILICONSTUDIO_PLATFORM_ANDROID
19 using System.Text;
20 using System.Runtime.InteropServices;
21 using OpenTK.Platform.Android;
22 #elif SILICONSTUDIO_PLATFORM_IOS
23 using OpenTK.Platform.iPhoneOS;
24 #endif
25 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
26 using OpenTK.Graphics.ES30;
27 using FramebufferAttachment = OpenTK.Graphics.ES30.FramebufferSlot;
28 #else
29 using OpenTK.Graphics.OpenGL;
30 #endif
31 
32 namespace SiliconStudio.Paradox.Graphics
33 {
34  /// <summary>
35  /// Performs primitive-based rendering, creates resources, handles system-level variables, adjusts gamma ramp levels, and creates shaders.
36  /// </summary>
37  public partial class GraphicsDevice
38  {
39  // Used when locking asyncCreationLockObject
40  private bool asyncCreationLockTaken;
41 
42  internal bool ApplicationPaused = false;
43 
44  internal IWindowInfo deviceCreationWindowInfo;
45  internal object asyncCreationLockObject = new object();
46  internal OpenTK.Graphics.IGraphicsContext deviceCreationContext;
47 
48 #if SILICONSTUDIO_PLATFORM_ANDROID
49  // If context was set before Begin(), try to keep it after End()
50  // (otherwise devices with no backbuffer flicker)
51  private bool keepContextOnEnd;
52 
53  private IntPtr graphicsContextEglPtr;
54  internal AndroidAsyncGraphicsContext androidAsyncDeviceCreationContext;
55  internal bool AsyncPendingTaskWaiting; // Used when Workaround_Context_Tegra2_Tegra3
56 
57  // Workarounds for specific GPUs
58  internal bool Workaround_VAO_PowerVR_SGX_540;
59  internal bool Workaround_Context_Tegra2_Tegra3;
60 #endif
61 
62  internal SamplerState defaultSamplerState;
63  internal DepthStencilState defaultDepthStencilState;
64  internal BlendState defaultBlendState;
65  internal int versionMajor, versionMinor;
66  internal RenderTarget windowProvidedRenderTarget;
67  internal Texture2D windowProvidedRenderTexture;
68  internal DepthStencilBuffer windowProvidedDepthBuffer;
69  internal Texture2D windowProvidedDepthTexture;
70 
71  internal bool HasVAO;
72 
73 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
74  internal bool HasDepth24;
75  internal bool HasPackedDepthStencilExtension;
76  internal bool HasExtTextureFormatBGRA8888;
77 #endif
78 
79  private int windowProvidedFrameBuffer;
80 
81  private RenderTarget defaultRenderTarget;
82  private GraphicsDevice immediateContext;
83  private GraphicsAdapter _adapter;
84  private SwapChainBackend _defaultSwapChainBackend;
85  private Viewport[] _currentViewports = new Viewport[16];
86  private int contextBeginCounter = 0;
87 
88  private int activeTexture = 0;
89 
90  // TODO: Use some LRU scheme to clean up FBOs if not used frequently anymore.
91  internal Dictionary<FBOKey, int> existingFBOs = new Dictionary<FBOKey,int>();
92 
93  /// <summary>
94  /// PrimitiveTopology state
95  /// </summary>
96  private PrimitiveType _currentPrimitiveType = PrimitiveType.Undefined;
97 
98  private static GraphicsDevice _currentGraphicsDevice;
99 
100  [ThreadStatic] private static List<GraphicsDevice> _graphicsDevicesInUse;
101 
102  public static GraphicsDevice Current
103  {
104  get
105  {
106  if (_graphicsDevicesInUse != null && _graphicsDevicesInUse.Count > 0)
107  return _graphicsDevicesInUse[_graphicsDevicesInUse.Count - 1];
108 
109  return _currentGraphicsDevice;
110  }
111 
112  set
113  {
114  _currentGraphicsDevice = value;
115  }
116  }
117 
118  private OpenTK.Graphics.IGraphicsContext graphicsContext;
119  private OpenTK.Platform.IWindowInfo windowInfo;
120 
121 #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
122  private OpenTK.GameWindow gameWindow;
123 #elif SILICONSTUDIO_PLATFORM_ANDROID
124  private AndroidGameView gameWindow;
125 #elif SILICONSTUDIO_PLATFORM_IOS
126  private iPhoneOSGameView gameWindow;
127 #endif
128 
129 
130  private VertexArrayObject currentVertexArrayObject;
131  private VertexArrayObject boundVertexArrayObject;
132  internal uint enabledVertexAttribArrays;
133  private DepthStencilState boundDepthStencilState;
134  private int boundStencilReference;
135  private BlendState boundBlendState;
136  private RasterizerState boundRasterizerState;
137  private DepthStencilBuffer boundDepthStencilBuffer;
138  private RenderTarget[] boundRenderTargets = new RenderTarget[16];
139  private int boundFBO;
140  internal bool hasRenderTarget, hasDepthStencilBuffer;
141  private int boundFBOHeight;
142  private int boundProgram = 0;
143  private bool needUpdateFBO = true;
144  private DrawElementsType drawElementsType;
145  private int indexElementSize;
146  private IntPtr indexBufferOffset;
147  private bool flipRenderTarget = false;
148  private FrontFaceDirection currentFrontFace = FrontFaceDirection.Ccw;
149  private FrontFaceDirection boundFrontFace = FrontFaceDirection.Ccw;
150 
151 #if SILICONSTUDIO_PLATFORM_ANDROID
152  [DllImport("libEGL.dll", EntryPoint = "eglGetCurrentContext")]
153  internal static extern IntPtr EglGetCurrentContext();
154 #endif
155  internal EffectProgram effectProgram;
156  private Texture[] boundTextures = new Texture[64];
157  private Texture[] textures = new Texture[64];
158  private SamplerState[] samplerStates = new SamplerState[64];
159 
160 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
161  private Buffer constantBuffer;
162 
163  // Need to change sampler state depending on if texture has mipmap or not during PreDraw
164  private bool[] hasMipmaps = new bool[64];
165 
166  private int copyProgram = -1;
167  private int copyProgramOffsetLocation = -1;
168  private int copyProgramScaleLocation = -1;
169  private float[] squareVertices = {
170  0.0f, 0.0f,
171  1.0f, 0.0f,
172  0.0f, 1.0f,
173  1.0f, 1.0f,
174  };
175 #endif
176  /// <summary>
177  /// Gets the status of this device.
178  /// </summary>
180  {
181  get
182  {
183 #if SILICONSTUDIO_PLATFORM_ANDROID
184  if (graphicsContext != gameWindow.GraphicsContext)
185  {
186  return GraphicsDeviceStatus.Reset;
187  }
188 #endif
189 
190  // TODO implement GraphicsDeviceStatus for OpenGL
191  return GraphicsDeviceStatus.Normal;
192  }
193  }
194 
195  /// <summary>
196  /// Gets the first viewport.
197  /// </summary>
198  /// <value>The first viewport.</value>
199  public Viewport Viewport
200  {
201  get
202  {
203 #if DEBUG
204  EnsureContextActive();
205 #endif
206 
207  return _currentViewports[0];
208  }
209  }
210 
211  public void Use()
212  {
213  if (_graphicsDevicesInUse == null)
214  _graphicsDevicesInUse = new List<GraphicsDevice>();
215 
216  if (!_graphicsDevicesInUse.Contains(this))
217  _graphicsDevicesInUse.Add(this);
218  }
219 
220  public void Unuse()
221  {
222  if (_graphicsDevicesInUse == null)
223  return;
224 
225  _graphicsDevicesInUse.Remove(this);
226 
227  if (_graphicsDevicesInUse.Count == 0)
228  _graphicsDevicesInUse = null;
229  }
230 
231  internal UseOpenGLCreationContext UseOpenGLCreationContext()
232  {
233  return new UseOpenGLCreationContext(this);
234  }
235 
236  public void ApplyPlatformSpecificParams(Effect effect)
237  {
238  effect.Parameters.Set(ShaderBaseKeys.ParadoxFlipRendertarget, flipRenderTarget ? -1.0f : 1.0f);
239  }
240 
241  /// <summary>
242  /// Marks context as active on the current thread.
243  /// </summary>
244  public void Begin()
245  {
246  ++contextBeginCounter;
247 
248 #if SILICONSTUDIO_PLATFORM_ANDROID
249  if (contextBeginCounter == 1)
250  {
251  if (Workaround_Context_Tegra2_Tegra3)
252  {
253  Monitor.Enter(asyncCreationLockObject, ref asyncCreationLockTaken);
254  }
255  else
256  {
257  // On first set, check if context was not already set before,
258  // in which case we won't unset it during End().
259  keepContextOnEnd = graphicsContextEglPtr == EglGetCurrentContext();
260 
261  if (keepContextOnEnd)
262  {
263  return;
264  }
265  }
266  }
267 #endif
268 
269  if (contextBeginCounter == 1)
270  graphicsContext.MakeCurrent(windowInfo);
271  }
272 
273  public void BeginProfile(Color profileColor, string name)
274  {
275  }
276 
277  public void Clear(DepthStencilBuffer depthStencilBuffer, DepthStencilClearOptions options, float depth = 1, byte stencil = 0)
278  {
279 #if DEBUG
280  EnsureContextActive();
281 #endif
282 
283 #if SILICONSTUDIO_PLATFORM_ANDROID
284  // Device with no background loading context: check if some loading is pending
285  if (AsyncPendingTaskWaiting)
286  ExecutePendingTasks();
287 #endif
288 
289  var clearFBO = FindOrCreateFBO(depthStencilBuffer);
290  if (clearFBO != boundFBO)
291  GL.BindFramebuffer(FramebufferTarget.Framebuffer, clearFBO);
292 
293  ClearBufferMask clearBufferMask =
294  ((options & DepthStencilClearOptions.DepthBuffer) == DepthStencilClearOptions.DepthBuffer ? ClearBufferMask.DepthBufferBit : 0)
295  | ((options & DepthStencilClearOptions.Stencil) == DepthStencilClearOptions.Stencil ? ClearBufferMask.StencilBufferBit : 0);
296  GL.ClearDepth(depth);
297  GL.ClearStencil(stencil);
298 
299  var depthStencilState = boundDepthStencilState ?? DepthStencilStates.Default;
300  var depthMask = depthStencilState.Description.DepthBufferWriteEnable && hasDepthStencilBuffer;
301 
302  if (!depthMask)
303  GL.DepthMask(true);
304  GL.Clear(clearBufferMask);
305  if (!depthMask)
306  GL.DepthMask(false);
307 
308  if (clearFBO != boundFBO)
309  GL.BindFramebuffer(FramebufferTarget.Framebuffer, boundFBO);
310  }
311 
312  public void Clear(RenderTarget renderTarget, Color4 color)
313  {
314 #if DEBUG
315  EnsureContextActive();
316 #endif
317 
318  var clearFBO = FindOrCreateFBO(renderTarget);
319  if (clearFBO != boundFBO)
320  GL.BindFramebuffer(FramebufferTarget.Framebuffer, clearFBO);
321 
322  var blendState = boundBlendState ?? BlendStates.Default;
323  var colorMask = hasRenderTarget && blendState.Description.RenderTargets[0].ColorWriteChannels == ColorWriteChannels.All;
324  if (!colorMask)
325  GL.ColorMask(true, true, true, true);
326 
327  GL.ClearColor(color.R, color.G, color.B, color.A);
328  GL.Clear(ClearBufferMask.ColorBufferBit);
329 
330  // revert the color mask value as it was before
331  if (!colorMask)
332  blendState.ApplyColorMask();
333 
334  if (clearFBO != boundFBO)
335  GL.BindFramebuffer(FramebufferTarget.Framebuffer, boundFBO);
336  }
337 
338  public unsafe void ClearReadWrite(Buffer buffer, Vector4 value)
339  {
340 #if DEBUG
341  EnsureContextActive();
342 #endif
343 
344  throw new NotImplementedException();
345  }
346 
347  public unsafe void ClearReadWrite(Buffer buffer, Int4 value)
348  {
349 #if DEBUG
350  EnsureContextActive();
351 #endif
352 
353  throw new NotImplementedException();
354  }
355 
356  public unsafe void ClearReadWrite(Buffer buffer, UInt4 value)
357  {
358 #if DEBUG
359  EnsureContextActive();
360 #endif
361 
362  throw new NotImplementedException();
363  }
364 
365  public unsafe void ClearReadWrite(Texture texture, Vector4 value)
366  {
367 #if DEBUG
368  EnsureContextActive();
369 #endif
370 
371  throw new NotImplementedException();
372  }
373 
374  public unsafe void ClearReadWrite(Texture texture, Int4 value)
375  {
376 #if DEBUG
377  EnsureContextActive();
378 #endif
379 
380  throw new NotImplementedException();
381  }
382 
383  public unsafe void ClearReadWrite(Texture texture, UInt4 value)
384  {
385 #if DEBUG
386  EnsureContextActive();
387 #endif
388 
389  throw new NotImplementedException();
390  }
391 
392  public void ClearState()
393  {
394 #if DEBUG
395  EnsureContextActive();
396 #endif
397  UnbindVertexArrayObject();
398  currentVertexArrayObject = null;
399 
400  // Clear sampler states
401  for (int i = 0; i < samplerStates.Length; ++i)
402  samplerStates[i] = null;
403 
404  for (int i = 0; i < boundTextures.Length; ++i)
405  {
406  textures[i] = null;
407  }
408 
409  // Clear active texture state
410  activeTexture = 0;
411  GL.ActiveTexture(TextureUnit.Texture0);
412 
413  // set default states
414  SetBlendState(null);
415  SetRasterizerState(null);
416  SetDepthStencilState(null);
417 
418  // Set default render targets
419  SetRenderTarget(DepthStencilBuffer, BackBuffer);
420  }
421 
422  /// <summary>
423  /// Copy a region of a <see cref="GraphicsResource"/> into another.
424  /// </summary>
425  /// <param name="source">The source from which to copy the data</param>
426  /// <param name="regionSource">The region of the source <see cref="GraphicsResource"/> to copy.</param>
427  /// <param name="destination">The destination into which to copy the data</param>
428  /// <remarks>This might alter some states such as currently bound texture.</remarks>
429  public void CopyRegion(GraphicsResource source, int sourceSubresource, ResourceRegion? regionSource, GraphicsResource destination, int destinationSubResource, int dstX = 0, int dstY = 0, int dstZ = 0)
430  {
431 #if DEBUG
432  EnsureContextActive();
433 #endif
434  var sourceTexture = source as Texture2D;
435  var destTexture = destination as Texture2D;
436 
437  if (sourceTexture == null || destTexture == null)
438  throw new NotImplementedException("Copy is only implemented for ITexture2D objects.");
439 
440  if (sourceSubresource != 0 || destinationSubResource != 0)
441  throw new NotImplementedException("Copy is only implemented for subresource 0 in OpenGL.");
442 
443  var sourceRegion = regionSource.HasValue? regionSource.Value : new ResourceRegion(0, 0, 0, sourceTexture.Description.Width, sourceTexture.Description.Height, 0);
444  var sourceRectangle = new Rectangle(sourceRegion.Left, sourceRegion.Top, sourceRegion.Right - sourceRegion.Left, sourceRegion.Bottom - sourceRegion.Top);
445 
446  if (sourceRectangle.Width == 0 || sourceRectangle.Height == 0)
447  return;
448 
449  if (destTexture.Description.Usage == GraphicsResourceUsage.Staging)
450  {
451  if(sourceTexture.Width <= 16 || sourceTexture.Height <= 16)
452  throw new NotSupportedException("ReadPixels from texture smaller or equal to 16x16 pixels seems systematically to fails on some android devices (for exp: Galaxy S3)");
453 
454  if (dstX != 0 || dstY != 0 || dstZ != 0)
455  throw new NotSupportedException("ReadPixels from staging texture using non-zero destination is not supported");
456 
457  GL.Viewport(0, 0, destTexture.Description.Width, destTexture.Description.Height);
458  GL.BindFramebuffer(FramebufferTarget.Framebuffer, FindOrCreateFBO(source));
459 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
460  GL.ReadPixels(sourceRectangle.Left, sourceRectangle.Top, sourceRectangle.Width, sourceRectangle.Height, destTexture.FormatGl, destTexture.Type, destTexture.StagingData);
461 #else
462  GL.BindBuffer(BufferTarget.PixelPackBuffer, destTexture.ResourceId);
463  GL.ReadPixels(sourceRectangle.Left, sourceRectangle.Top, sourceRectangle.Width, sourceRectangle.Height, destTexture.FormatGl, destTexture.Type, IntPtr.Zero);
464  GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
465 #endif
466  GL.BindFramebuffer(FramebufferTarget.Framebuffer, boundFBO);
467  GL.Viewport((int)_currentViewports[0].X, (int)_currentViewports[0].Y, (int)_currentViewports[0].Width, (int)_currentViewports[0].Height);
468  return;
469  }
470 
471 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
472  // Use rendering
473  GL.Viewport(0, 0, destTexture.Description.Width, destTexture.Description.Height);
474  GL.BindFramebuffer(FramebufferTarget.Framebuffer, FindOrCreateFBO(destination));
475 
476  if (copyProgram == -1)
477  {
478  const string copyVertexShaderSource =
479  "attribute vec2 aPosition; \n" +
480  "varying vec2 vTexCoord; \n" +
481  "uniform vec4 uScale; \n" +
482  "uniform vec4 uOffset; \n" +
483  "void main() \n" +
484  "{ \n" +
485  " vec4 transformedPosition = aPosition.xyxy * uScale + uOffset;" +
486  " gl_Position = vec4(transformedPosition.zw * 2.0 - 1.0, 0.0, 1.0); \n" +
487  " vTexCoord = transformedPosition.xy; \n" +
488  "} \n";
489 
490  const string copyFragmentShaderSource =
491  "precision mediump float; \n" +
492  "varying vec2 vTexCoord; \n" +
493  "uniform sampler2D s_texture; \n" +
494  "void main() \n" +
495  "{ \n" +
496  " gl_FragColor = texture2D(s_texture, vTexCoord); \n" +
497  "} \n";
498 
499  // First initialization of shader program
500  int vertexShader = TryCompileShader(ShaderType.VertexShader, copyVertexShaderSource);
501  int fragmentShader = TryCompileShader(ShaderType.FragmentShader, copyFragmentShaderSource);
502 
503  copyProgram = GL.CreateProgram();
504  GL.AttachShader(copyProgram, vertexShader);
505  GL.AttachShader(copyProgram, fragmentShader);
506  GL.BindAttribLocation(copyProgram, 0, "aPosition");
507  GL.LinkProgram(copyProgram);
508 
509  int linkStatus;
510  GL.GetProgram(copyProgram, ProgramParameter.LinkStatus, out linkStatus);
511 
512  if (linkStatus != 1)
513  throw new InvalidOperationException("Error while linking GLSL shaders.");
514 
515  GL.UseProgram(copyProgram);
516 #if SILICONSTUDIO_PLATFORM_ANDROID
517  var textureLocation = GL.GetUniformLocation(copyProgram, new StringBuilder("s_texture"));
518  copyProgramOffsetLocation = GL.GetUniformLocation(copyProgram, new StringBuilder("uOffset"));
519  copyProgramScaleLocation = GL.GetUniformLocation(copyProgram, new StringBuilder("uScale"));
520 #else
521  var textureLocation = GL.GetUniformLocation(copyProgram, "s_texture");
522  copyProgramOffsetLocation = GL.GetUniformLocation(copyProgram, "uOffset");
523  copyProgramScaleLocation = GL.GetUniformLocation(copyProgram, "uScale");
524 #endif
525  GL.Uniform1(textureLocation, 0);
526  }
527 
528  var regionSize = new Vector2(sourceRectangle.Width, sourceRectangle.Height);
529 
530  // Source
531  var sourceSize = new Vector2(sourceTexture.Width, sourceTexture.Height);
532  var sourceRegionLeftTop = new Vector2(sourceRectangle.Left, sourceRectangle.Top);
533  var sourceScale = new Vector2(regionSize.X / sourceSize.X, regionSize.Y / sourceSize.Y);
534  var sourceOffset = new Vector2(sourceRegionLeftTop.X / sourceSize.X, sourceRegionLeftTop.Y / sourceSize.Y);
535 
536  // Dest
537  var destSize = new Vector2(destTexture.Width, destTexture.Height);
538  var destRegionLeftTop = new Vector2(dstX, dstY);
539  var destScale = new Vector2(regionSize.X / destSize.X, regionSize.Y / destSize.Y);
540  var destOffset = new Vector2(destRegionLeftTop.X / destSize.X, destRegionLeftTop.Y / destSize.Y);
541 
542  var enabledColors = new bool[4];
543  GL.GetBoolean(GetPName.ColorWritemask, enabledColors);
544  var isDepthTestEnabled = GL.IsEnabled(EnableCap.DepthTest);
545  var isCullFaceEnabled = GL.IsEnabled(EnableCap.CullFace);
546  var isBlendEnabled = GL.IsEnabled(EnableCap.Blend);
547  var isStencilEnabled = GL.IsEnabled(EnableCap.StencilTest);
548  GL.Disable(EnableCap.DepthTest);
549  GL.Disable(EnableCap.CullFace);
550  GL.Disable(EnableCap.Blend);
551  GL.Disable(EnableCap.StencilTest);
552  GL.ColorMask(true, true, true, true);
553 
554  UnbindVertexArrayObject();
555 
556  GL.UseProgram(copyProgram);
557 
558  activeTexture = 0;
559  GL.ActiveTexture(TextureUnit.Texture0);
560  GL.BindTexture(TextureTarget.Texture2D, sourceTexture.resourceId);
561  boundTextures[0] = null;
562  GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
563  GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
564  GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
565  GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
566  ((Texture)source).BoundSamplerState = SamplerStates.PointClamp;
567 
568  GL.EnableVertexAttribArray(0);
569  GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
570  GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 0, squareVertices);
571  GL.Uniform4(copyProgramOffsetLocation, sourceOffset.X, sourceOffset.Y, destOffset.X, destOffset.Y);
572  GL.Uniform4(copyProgramScaleLocation, sourceScale.X, sourceScale.Y, destScale.X, destScale.Y);
573  GL.DrawArrays(BeginMode.TriangleStrip, 0, 4);
574  GL.DisableVertexAttribArray(0);
575  GL.UseProgram(boundProgram);
576 
577  // Restore context
578  if (isDepthTestEnabled)
579  GL.Enable(EnableCap.DepthTest);
580  if (isCullFaceEnabled)
581  GL.Enable(EnableCap.CullFace);
582  if (isBlendEnabled)
583  GL.Enable(EnableCap.Blend);
584  if(isStencilEnabled)
585  GL.Enable(EnableCap.StencilTest);
586  GL.ColorMask(enabledColors[0], enabledColors[1], enabledColors[2], enabledColors[3]);
587 
588  GL.BindFramebuffer(FramebufferTarget.Framebuffer, boundFBO);
589  GL.Viewport((int)_currentViewports[0].X, (int)_currentViewports[0].Y, (int)_currentViewports[0].Width, (int)_currentViewports[0].Height);
590 #else
591  // "FindOrCreateFBO" set the frameBuffer on FBO creation -> those 2 calls cannot be made directly in the following "GL.BindFramebuffer" function calls (side effects)
592  var sourceFBO = FindOrCreateFBO(source);
593  var destinationFBO = FindOrCreateFBO(destination);
594  GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, sourceFBO);
595  GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, destinationFBO);
596  GL.BlitFramebuffer(sourceRegion.Left, sourceRegion.Top, sourceRegion.Right, sourceRegion.Bottom,
597  dstX, dstY, dstX + sourceRegion.Right - sourceRegion.Left, dstY + sourceRegion.Bottom - sourceRegion.Top,
598  ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Nearest);
599  GL.BindFramebuffer(FramebufferTarget.Framebuffer, boundFBO);
600 #endif
601  }
602 
603  /// <summary>
604  /// Copy a <see cref="GraphicsResource"/> into another.
605  /// </summary>
606  /// <param name="source">The source from which to copy the data</param>
607  /// <param name="destination">The destination into which to copy the data</param>
608  /// <remarks>This might alter some states such as currently bound texture.</remarks>
609  public void Copy(GraphicsResource source, GraphicsResource destination)
610  {
611  CopyRegion(source, 0, null, destination, 0);
612  }
613 
614  public void CopyCount(Buffer sourceBuffer, Buffer destBuffer, int offsetToDest)
615  {
616 #if DEBUG
617  EnsureContextActive();
618 #endif
619 
620  throw new NotImplementedException();
621  }
622 
623  public void Dispatch(int threadCountX, int threadCountY, int threadCountZ)
624  {
625 #if DEBUG
626  EnsureContextActive();
627 #endif
628 
629  throw new NotImplementedException();
630  }
631 
632  public void Dispatch(Buffer indirectBuffer, int offsetInBytes)
633  {
634 #if DEBUG
635  EnsureContextActive();
636 #endif
637 
638  throw new NotImplementedException();
639  }
640 
641  public void Draw(PrimitiveType primitiveType, int vertexCount, int startVertex = 0)
642  {
643 #if DEBUG
644  EnsureContextActive();
645 #endif
646 
647  PreDraw();
648  GL.DrawArrays(primitiveType.ToOpenGL(), startVertex, vertexCount);
649  }
650 
651  public void DrawAuto(PrimitiveType primitiveType)
652  {
653 #if DEBUG
654  EnsureContextActive();
655 #endif
656  PreDraw();
657  //GL.DrawArraysIndirect(primitiveType.ToOpenGL(), (IntPtr)0);
658  throw new NotImplementedException();
659  }
660 
661  /// <summary>
662  /// Draw indexed, non-instanced primitives.
663  /// </summary>
664  /// <param name="primitiveType">Type of the primitive to draw.</param>
665  /// <param name="indexCount">Number of indices to draw.</param>
666  /// <param name="startIndexLocation">The location of the first index read by the GPU from the index buffer.</param>
667  /// <param name="baseVertexLocation">A value added to each index before reading a vertex from the vertex buffer.</param>
668  public void DrawIndexed(PrimitiveType primitiveType, int indexCount, int startIndexLocation = 0, int baseVertexLocation = 0)
669  {
670 #if DEBUG
671  EnsureContextActive();
672 #endif
673  PreDraw();
674 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
675  if(baseVertexLocation != 0)
676  throw new NotSupportedException("DrawIndexed with no null baseVertexLocation is not supported on OpenGL ES2.");
677  GL.DrawElements(primitiveType.ToOpenGL(), indexCount, drawElementsType, indexBufferOffset + (startIndexLocation * indexElementSize)); // conversion to IntPtr required on Android
678 #else
679  GL.DrawElementsBaseVertex(primitiveType.ToOpenGL(), indexCount, drawElementsType, indexBufferOffset + (startIndexLocation * indexElementSize), baseVertexLocation);
680 #endif
681  }
682 
683  /// <summary>
684  /// Draw indexed, instanced primitives.
685  /// </summary>
686  /// <param name="primitiveType">Type of the primitive to draw.</param>
687  /// <param name="indexCountPerInstance">Number of indices read from the index buffer for each instance.</param>
688  /// <param name="instanceCount">Number of instances to draw.</param>
689  /// <param name="startIndexLocation">The location of the first index read by the GPU from the index buffer.</param>
690  /// <param name="baseVertexLocation">A value added to each index before reading a vertex from the vertex buffer.</param>
691  /// <param name="startInstanceLocation">A value added to each index before reading per-instance data from a vertex buffer.</param>
692  public void DrawIndexedInstanced(PrimitiveType primitiveType, int indexCountPerInstance, int instanceCount, int startIndexLocation = 0, int baseVertexLocation = 0, int startInstanceLocation = 0)
693  {
694 #if DEBUG
695  EnsureContextActive();
696 #endif
697  PreDraw();
698 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
699  throw new NotImplementedException();
700 #else
701  GL.DrawElementsInstancedBaseVertex(primitiveType.ToOpenGL(), indexCountPerInstance, DrawElementsType.UnsignedInt, (IntPtr)(startIndexLocation * indexElementSize), instanceCount, baseVertexLocation);
702 #endif
703  }
704 
705  /// <summary>
706  /// Draw indexed, instanced, GPU-generated primitives.
707  /// </summary>
708  /// <param name="primitiveType">Type of the primitive to draw.</param>
709  /// <param name="argumentsBuffer">A buffer containing the GPU generated primitives.</param>
710  /// <param name="alignedByteOffsetForArgs">Offset in <em>pBufferForArgs</em> to the start of the GPU generated primitives.</param>
711  public void DrawIndexedInstanced(PrimitiveType primitiveType, Buffer argumentsBuffer, int alignedByteOffsetForArgs = 0)
712  {
713  if (argumentsBuffer == null) throw new ArgumentNullException("argumentsBuffer");
714 
715 #if DEBUG
716  EnsureContextActive();
717 #endif
718  PreDraw();
719  throw new NotImplementedException();
720  }
721 
722  /// <summary>
723  /// Draw non-indexed, instanced primitives.
724  /// </summary>
725  /// <param name="primitiveType">Type of the primitive to draw.</param>
726  /// <param name="vertexCountPerInstance">Number of vertices to draw.</param>
727  /// <param name="instanceCount">Number of instances to draw.</param>
728  /// <param name="startVertexLocation">Index of the first vertex.</param>
729  /// <param name="startInstanceLocation">A value added to each index before reading per-instance data from a vertex buffer.</param>
730  public void DrawInstanced(PrimitiveType primitiveType, int vertexCountPerInstance, int instanceCount, int startVertexLocation = 0, int startInstanceLocation = 0)
731  {
732 #if DEBUG
733  EnsureContextActive();
734 #endif
735  //TODO: review code
736  PreDraw();
737 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
738  throw new NotImplementedException();
739 #else
740  GL.DrawArraysInstanced(primitiveType.ToOpenGL(), startVertexLocation, vertexCountPerInstance, instanceCount);
741 #endif
742  }
743 
744  /// <summary>
745  /// Draw instanced, GPU-generated primitives.
746  /// </summary>
747  /// <param name="primitiveType">Type of the primitive to draw.</param>
748  /// <param name="argumentsBuffer">An arguments buffer</param>
749  /// <param name="alignedByteOffsetForArgs">Offset in <em>pBufferForArgs</em> to the start of the GPU generated primitives.</param>
750  public void DrawInstanced(PrimitiveType primitiveType, Buffer argumentsBuffer, int alignedByteOffsetForArgs = 0)
751  {
752  if (argumentsBuffer == null) throw new ArgumentNullException("argumentsBuffer");
753 
754 #if DEBUG
755  EnsureContextActive();
756 #endif
757  PreDraw();
758  throw new NotImplementedException();
759  }
760 
761  public void EnableProfile(bool enabledFlag)
762  {
763  }
764 
765  /// <summary>
766  /// Unmarks context as active on the current thread.
767  /// </summary>
768  public void End()
769  {
770 #if DEBUG
771  EnsureContextActive();
772 #endif
773 
774  --contextBeginCounter;
775  if (contextBeginCounter == 0)
776  {
777  UnbindVertexArrayObject();
778 
779 #if SILICONSTUDIO_PLATFORM_ANDROID
780  if (Workaround_Context_Tegra2_Tegra3)
781  {
782  graphicsContext.MakeCurrent(null);
783 
784  // Notify that main context can be used from now on
785  if (asyncCreationLockTaken)
786  {
787  Monitor.Exit(asyncCreationLockObject);
788  asyncCreationLockTaken = false;
789  }
790  }
791  else if (!keepContextOnEnd)
792  {
793  UnbindGraphicsContext(graphicsContext);
794  }
795 #else
796  UnbindGraphicsContext(graphicsContext);
797 #endif
798  }
799  else if (contextBeginCounter < 0)
800  {
801  throw new Exception("End context was called more than Begin");
802  }
803  }
804 
805  public void EndProfile()
806  {
807  }
808 
809  internal void EnsureContextActive()
810  {
811  // TODO: Better checks (is active context the expected one?)
812 #if SILICONSTUDIO_PLATFORM_ANDROID
813  if (EglGetCurrentContext() == IntPtr.Zero)
814  throw new InvalidOperationException("No OpenGL context bound.");
815 #else
816  if (OpenTK.Graphics.GraphicsContext.CurrentContext == null)
817  throw new InvalidOperationException("No OpenGL context bound.");
818 #endif
819  }
820 
821  public void ExecuteCommandList(ICommandList commandList)
822  {
823 #if DEBUG
824  EnsureContextActive();
825 #endif
826 
827  throw new NotImplementedException();
828  }
829 
830  internal void BindProgram(int program)
831  {
832  if (program != boundProgram)
833  {
834  boundProgram = program;
835  GL.UseProgram(program);
836  }
837  }
838 
839  internal int FindOrCreateFBO(GraphicsResourceBase graphicsResource)
840  {
841  if (graphicsResource == RootDevice.windowProvidedRenderTarget
842  || graphicsResource == RootDevice.windowProvidedRenderTexture)
843  return windowProvidedFrameBuffer;
844 
845  if (graphicsResource is DepthStencilBuffer)
846  return FindOrCreateFBO((DepthStencilBuffer)graphicsResource, null);
847  if (graphicsResource is RenderTarget)
848  return FindOrCreateFBO(null, new[] { (RenderTarget)graphicsResource });
849  if (graphicsResource is Texture)
850  return FindOrCreateFBO(null, new[] { ((Texture)graphicsResource).GetCachedRenderTarget() });
851 
852  throw new NotSupportedException();
853  }
854 
855  internal int FindOrCreateFBO(DepthStencilBuffer depthStencilBuffer)
856  {
857  lock (RootDevice.existingFBOs)
858  {
859  foreach (var key in RootDevice.existingFBOs)
860  {
861  if (key.Key.DepthStencilBuffer == depthStencilBuffer)
862  return key.Value;
863  }
864  }
865 
866  return FindOrCreateFBO(depthStencilBuffer, null);
867  }
868 
869  internal int FindOrCreateFBO(RenderTarget target)
870  {
871  lock (RootDevice.existingFBOs)
872  {
873  foreach (var key in RootDevice.existingFBOs)
874  {
875  if (key.Key.LastRenderTarget == 1 && key.Key.RenderTargets[0] == target)
876  return key.Value;
877  }
878  }
879 
880  return FindOrCreateFBO(null, new[] { target });
881  }
882 
883  internal int FindOrCreateFBO(DepthStencilBuffer depthStencilBuffer, RenderTarget[] renderTargets)
884  {
885  int framebufferId;
886 
887  // Check for existing FBO matching this configuration
888  lock (RootDevice.existingFBOs)
889  {
890  var fboKey = new FBOKey(depthStencilBuffer, renderTargets);
891 
892  // Is it the default provided render target?
893  // TODO: Need to disable some part of rendering if either is null
894  var isProvidedDepthBuffer = (depthStencilBuffer == RootDevice.windowProvidedDepthBuffer);
895  var isProvidedRenderTarget = (fboKey.LastRenderTarget == 1 && renderTargets[0] == RootDevice.windowProvidedRenderTarget);
896  if ((isProvidedDepthBuffer || boundDepthStencilBuffer == null) && (isProvidedRenderTarget || fboKey.LastRenderTarget == 0)) // device provided framebuffer
897  {
898  return windowProvidedFrameBuffer;
899  }
900  if (isProvidedDepthBuffer || isProvidedRenderTarget)
901  {
902  throw new InvalidOperationException("It is impossible to bind device provided and user created buffers with OpenGL");
903  }
904 
905  if (RootDevice.existingFBOs.TryGetValue(fboKey, out framebufferId))
906  return framebufferId;
907 
908  GL.GenFramebuffers(1, out framebufferId);
909  GL.BindFramebuffer(FramebufferTarget.Framebuffer, framebufferId);
910  int firstRenderTargets = -1;
911  if (renderTargets != null)
912  {
913  for (int i = 0; i < renderTargets.Length; ++i)
914  {
915  // TODO: Add support for render buffer
916  if (renderTargets[i] != null)
917  {
918  firstRenderTargets = i;
919  GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0 + i, TextureTarget.Texture2D, renderTargets[i].ResourceId, 0);
920  }
921  }
922  }
923 
924 #if !SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
925  GL.DrawBuffer(firstRenderTargets != -1 ? DrawBufferMode.ColorAttachment0 : DrawBufferMode.None);
926  GL.ReadBuffer(firstRenderTargets != -1 ? ReadBufferMode.ColorAttachment0 : ReadBufferMode.None);
927 #endif
928 
929  if (depthStencilBuffer != null)
930  {
931 #if !SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
932  FramebufferAttachment attachmentType;
933  if (depthStencilBuffer.IsDepthBuffer && depthStencilBuffer.IsStencilBuffer)
934  attachmentType = FramebufferAttachment.DepthStencilAttachment;
935  else if(depthStencilBuffer.IsDepthBuffer)
936  attachmentType = FramebufferAttachment.DepthAttachment;
937  else
938  attachmentType = FramebufferAttachment.StencilAttachment;
939 
940  if (depthStencilBuffer.Texture.IsRenderbuffer)
941  GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, attachmentType, RenderbufferTarget.Renderbuffer, depthStencilBuffer.ResourceId);
942  else
943  GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, attachmentType, TextureTarget.Texture2D, depthStencilBuffer.ResourceId, 0);
944 #else
945  if (depthStencilBuffer.IsDepthBuffer)
946  GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferSlot.DepthAttachment, RenderbufferTarget.Renderbuffer, depthStencilBuffer.ResourceId);
947 
948  // If stencil buffer is separate, it's resource id might be stored in depthStencilBuffer.Texture.ResouceIdStencil
949  if(depthStencilBuffer.IsStencilBuffer)
950  GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferSlot.StencilAttachment, RenderbufferTarget.Renderbuffer, depthStencilBuffer.Texture.ResouceIdStencil != 0 ? depthStencilBuffer.Texture.ResouceIdStencil : depthStencilBuffer.ResourceId);
951 #endif
952  }
953 
954  var framebufferStatus = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
955  if (framebufferStatus != FramebufferErrorCode.FramebufferComplete)
956  {
957  throw new InvalidOperationException(string.Format("FBO is incomplete: RT {0} Depth {1} (error: {2})", renderTargets != null && renderTargets.Length > 0 ? renderTargets[0].ResourceId : 0, depthStencilBuffer != null ? depthStencilBuffer.ResourceId : 0, framebufferStatus));
958  }
959 
960  GL.BindFramebuffer(FramebufferTarget.Framebuffer, boundFBO);
961 
962  RootDevice.existingFBOs.Add(new GraphicsDevice.FBOKey(depthStencilBuffer, renderTargets != null ? renderTargets.ToArray() : null), framebufferId);
963  }
964 
965  return framebufferId;
966  }
967 
968  public ICommandList FinishCommandList()
969  {
970 #if DEBUG
971  EnsureContextActive();
972 #endif
973 
974  throw new NotImplementedException();
975  }
976 
977  protected void InitializeFactories()
978  {
979  }
980 
981  public MappedResource MapSubresource(GraphicsResource resource, int subResourceIndex, MapMode mapMode, bool doNotWait = false, int offsetInBytes = 0, int lengthInBytes = 0)
982  {
983 #if DEBUG
984  EnsureContextActive();
985 #endif
986 
987 #if !SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
988  BufferAccess bufferAccess;
989  switch (mapMode)
990  {
991  case MapMode.Read:
992  bufferAccess = BufferAccess.ReadOnly;
993  break;
994  case MapMode.Write:
995  case MapMode.WriteDiscard:
996  case MapMode.WriteNoOverwrite:
997  bufferAccess = BufferAccess.WriteOnly;
998  break;
999  case MapMode.ReadWrite:
1000  bufferAccess = BufferAccess.ReadWrite;
1001  break;
1002  default:
1003  throw new ArgumentOutOfRangeException("mapMode");
1004  }
1005 #endif
1006 
1007  var buffer = resource as Buffer;
1008  if (buffer != null)
1009  {
1010  if (lengthInBytes == 0)
1011  lengthInBytes = buffer.Description.SizeInBytes;
1012 
1013 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1014  if (buffer.StagingData != IntPtr.Zero)
1015  {
1016  // TODO: Temporarily accept NoOverwrite as a discard
1017  // Shouldn't do that, but for now it fix a big perf issue due to SpriteBatch use
1018  //if (buffer.ResourceId != 0 && mapMode == MapMode.WriteDiscard)
1019  //{
1020  // // Notify OpenGL ES driver that previous data can be discarded by setting a new empty buffer
1021  // UnbindVertexArrayObject();
1022  // GL.BindBuffer(buffer.bufferTarget, buffer.ResourceId);
1023  // GL.BufferData(buffer.bufferTarget, (IntPtr)buffer.Description.SizeInBytes, IntPtr.Zero, buffer.bufferUsageHint);
1024  // GL.BindBuffer(buffer.bufferTarget, 0);
1025  //}
1026 
1027  // Specific case for constant buffers
1028  return new MappedResource(resource, subResourceIndex, new DataBox { DataPointer = buffer.StagingData + offsetInBytes, SlicePitch = 0, RowPitch = 0 }, offsetInBytes, lengthInBytes);
1029  }
1030 #endif
1031 
1032 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1033  throw new NotImplementedException();
1034 #else
1035  IntPtr mapResult = IntPtr.Zero;
1036 
1037  UnbindVertexArrayObject();
1038  GL.BindBuffer(buffer.bufferTarget, buffer.ResourceId);
1039 
1040  if (mapMode == MapMode.WriteDiscard)
1041  mapResult = GL.MapBufferRange(buffer.bufferTarget, (IntPtr)offsetInBytes, (IntPtr)lengthInBytes, BufferAccessMask.MapWriteBit | BufferAccessMask.MapInvalidateBufferBit);
1042  else if (mapMode == MapMode.WriteNoOverwrite)
1043  mapResult = GL.MapBufferRange(buffer.bufferTarget, (IntPtr)offsetInBytes, (IntPtr)lengthInBytes, BufferAccessMask.MapWriteBit | BufferAccessMask.MapUnsynchronizedBit);
1044  else
1045  mapResult = GL.MapBuffer(buffer.bufferTarget, bufferAccess);
1046 
1047  GL.BindBuffer(buffer.bufferTarget, 0);
1048 
1049  return new MappedResource(resource, subResourceIndex, new DataBox { DataPointer = mapResult, SlicePitch = 0, RowPitch = 0 });
1050 #endif
1051  }
1052 
1053  var texture = resource as Texture;
1054  if (texture != null)
1055  {
1056  if (mapMode == MapMode.Read)
1057  {
1058  if (texture.Description.Usage != GraphicsResourceUsage.Staging)
1059  throw new NotSupportedException("Only staging textures can be mapped.");
1060 
1061 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1062  if (lengthInBytes == 0)
1063  lengthInBytes = texture.DepthPitch;
1064  return new MappedResource(resource, subResourceIndex, new DataBox { DataPointer = texture.StagingData + offsetInBytes, SlicePitch = texture.DepthPitch, RowPitch = texture.RowPitch }, offsetInBytes, lengthInBytes);
1065 #else
1066  GL.BindBuffer(BufferTarget.PixelPackBuffer, texture.ResourceId);
1067  var mapResult = GL.MapBuffer(BufferTarget.PixelPackBuffer, bufferAccess);
1068  GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
1069  return new MappedResource(resource, subResourceIndex, new DataBox { DataPointer = mapResult, SlicePitch = texture.DepthPitch, RowPitch = texture.RowPitch });
1070 #endif
1071  }
1072  }
1073 
1074  throw new NotImplementedException();
1075  }
1076 
1077  public GraphicsDevice NewDeferred()
1078  {
1079  throw new NotImplementedException();
1080  }
1081 
1082  internal void PreDraw()
1083  {
1084 #if SILICONSTUDIO_PLATFORM_ANDROID
1085  // Device with no background loading context: check if some loading is pending
1086  if (AsyncPendingTaskWaiting)
1087  ExecutePendingTasks();
1088 #endif
1089 
1090  var inputSignature = effectProgram.InputSignature;
1091  if (currentVertexArrayObject != boundVertexArrayObject || (currentVertexArrayObject != null && currentVertexArrayObject.RequiresApply(inputSignature)))
1092  {
1093  if (currentVertexArrayObject == null)
1094  {
1095  UnbindVertexArrayObject();
1096  }
1097  else
1098  {
1099  drawElementsType = currentVertexArrayObject.drawElementsType;
1100  indexBufferOffset = currentVertexArrayObject.indexBufferOffset;
1101  indexElementSize = currentVertexArrayObject.indexElementSize;
1102  currentVertexArrayObject.Apply(inputSignature);
1103  boundVertexArrayObject = currentVertexArrayObject;
1104  }
1105  }
1106 
1107  foreach (var textureInfo in effectProgram.Textures)
1108  {
1109  var boundTexture = boundTextures[textureInfo.TextureUnit];
1110  var texture = textures[textureInfo.TextureUnit];
1111  var boundSamplerState = texture.BoundSamplerState ?? defaultSamplerState;
1112  var samplerState = samplerStates[textureInfo.TextureUnit] ?? SamplerStates.LinearClamp;
1113 
1114 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1115  bool hasMipmap = texture.Description.MipLevels > 1;
1116 #else
1117  bool hasMipmap = false;
1118 #endif
1119 
1120  bool textureChanged = texture != boundTexture;
1121  bool samplerStateChanged = samplerState != boundSamplerState;
1122 
1123  // TODO: Lazy update for texture
1124  if (textureChanged || samplerStateChanged)
1125  {
1126  if (activeTexture != textureInfo.TextureUnit)
1127  {
1128  activeTexture = textureInfo.TextureUnit;
1129  GL.ActiveTexture(TextureUnit.Texture0 + textureInfo.TextureUnit);
1130  }
1131 
1132  // Lazy update for texture
1133  if (textureChanged)
1134  {
1135  boundTextures[textureInfo.TextureUnit] = texture;
1136  GL.BindTexture(texture.Target, texture.resourceId);
1137  }
1138 
1139  // Lazy update for sampler state
1140  if (samplerStateChanged)
1141  {
1142  samplerState.Apply(hasMipmap, boundSamplerState);
1143  texture.BoundSamplerState = samplerState;
1144  }
1145  }
1146  }
1147 
1148  // Change face culling if the rendertarget is flipped
1149  var newFrontFace = currentFrontFace;
1150  if (flipRenderTarget)
1151  newFrontFace = newFrontFace == FrontFaceDirection.Cw ? FrontFaceDirection.Ccw : FrontFaceDirection.Cw;
1152 
1153  if (newFrontFace != boundFrontFace)
1154  {
1155  boundFrontFace = newFrontFace;
1156  GL.FrontFace(boundFrontFace);
1157  }
1158 
1159 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1160  unsafe
1161  {
1162  fixed(byte* boundUniforms = effectProgram.BoundUniforms)
1163  {
1164  var constantBufferData = constantBuffer.StagingData;
1165  foreach (var uniform in effectProgram.Uniforms)
1166  {
1167  var firstUniformIndex = uniform.UniformIndex;
1168  var lastUniformIndex = firstUniformIndex + uniform.Count;
1169  var offset = uniform.Offset;
1170  var boundData = (IntPtr)boundUniforms + offset;
1171  var currentData = constantBufferData + offset;
1172 
1173  // Already updated? Early exit.
1174  // TODO: Not optimal for float1/float2 arrays (rare?)
1175  // Better to do "sparse" comparison, not sure if C# code would behave well though
1176  if (SiliconStudio.Core.Utilities.CompareMemory(boundData, currentData, uniform.CompareSize))
1177  continue;
1178 
1179  // Update bound cache for early exit
1180  SiliconStudio.Core.Utilities.CopyMemory(boundData, currentData, uniform.CompareSize);
1181 
1182  switch (uniform.Type)
1183  {
1184  case ActiveUniformType.Float:
1185  for (int uniformIndex = firstUniformIndex; uniformIndex < lastUniformIndex; ++uniformIndex)
1186  {
1187  GL.Uniform1(uniformIndex, 1, (float*)currentData);
1188  currentData += 16; // Each array element is spaced by 16 bytes
1189  }
1190  break;
1191  case ActiveUniformType.FloatVec2:
1192  for (int uniformIndex = firstUniformIndex; uniformIndex < lastUniformIndex; ++uniformIndex)
1193  {
1194  GL.Uniform2(uniformIndex, 1, (float*)currentData);
1195  currentData += 16; // Each array element is spaced by 16 bytes
1196  }
1197  break;
1198  case ActiveUniformType.FloatVec3:
1199  for (int uniformIndex = firstUniformIndex; uniformIndex < lastUniformIndex; ++uniformIndex)
1200  {
1201  GL.Uniform3(uniformIndex, 1, (float*)currentData);
1202  currentData += 16; // Each array element is spaced by 16 bytes
1203  }
1204  break;
1205  case ActiveUniformType.FloatVec4:
1206  GL.Uniform4(firstUniformIndex, uniform.Count, (float*)currentData);
1207  break;
1208  case ActiveUniformType.FloatMat4:
1209  GL.UniformMatrix4(uniform.UniformIndex, uniform.Count, false, (float*)currentData);
1210  break;
1211  case ActiveUniformType.Bool:
1212  case ActiveUniformType.Int:
1213  for (int uniformIndex = firstUniformIndex; uniformIndex < lastUniformIndex; ++uniformIndex)
1214  {
1215  GL.Uniform1(uniformIndex, 1, (int*)currentData);
1216  currentData += 16; // Each array element is spaced by 16 bytes
1217  }
1218  break;
1219  case ActiveUniformType.BoolVec2:
1220  case ActiveUniformType.IntVec2:
1221  for (int uniformIndex = firstUniformIndex; uniformIndex < lastUniformIndex; ++uniformIndex)
1222  {
1223  GL.Uniform2(uniformIndex, 1, (int*)currentData);
1224  currentData += 16; // Each array element is spaced by 16 bytes
1225  }
1226  break;
1227  case ActiveUniformType.BoolVec3:
1228  case ActiveUniformType.IntVec3:
1229  for (int uniformIndex = firstUniformIndex; uniformIndex < lastUniformIndex; ++uniformIndex)
1230  {
1231  GL.Uniform3(uniformIndex, 1, (int*)currentData);
1232  currentData += 16; // Each array element is spaced by 16 bytes
1233  }
1234  break;
1235  case ActiveUniformType.BoolVec4:
1236  case ActiveUniformType.IntVec4:
1237  GL.Uniform4(firstUniformIndex, uniform.Count, (int*)currentData);
1238  break;
1239  default:
1240  throw new NotImplementedException();
1241  }
1242  }
1243  }
1244  }
1245 #endif
1246  }
1247 
1248  public void SetBlendState(BlendState blendState)
1249  {
1250 #if DEBUG
1251  EnsureContextActive();
1252 #endif
1253 
1254  if (blendState == null)
1255  blendState = BlendStates.Default;
1256 
1257  if (boundBlendState != blendState)
1258  {
1259  blendState.Apply(boundBlendState ?? BlendStates.Default);
1260  boundBlendState = blendState;
1261  }
1262  }
1263 
1264  public void SetBlendState(BlendState blendState, Color blendFactor, int multiSampleMask = -1)
1265  {
1266 #if DEBUG
1267  EnsureContextActive();
1268 #endif
1269 
1270  if (multiSampleMask != -1)
1271  throw new NotImplementedException();
1272 
1273  SetBlendState(blendState);
1274  GL.BlendColor(blendFactor.R, blendFactor.G, blendFactor.B, blendFactor.A);
1275  }
1276 
1277  public void SetBlendState(BlendState blendState, Color blendFactor, uint multiSampleMask = 0xFFFFFFFF)
1278  {
1279 #if DEBUG
1280  EnsureContextActive();
1281 #endif
1282 
1283  SetBlendState(blendState, blendFactor, unchecked((int)multiSampleMask));
1284  }
1285 
1286  /// <summary>
1287  /// Sets a constant buffer to the shader pipeline.
1288  /// </summary>
1289  /// <param name="stage">The shader stage.</param>
1290  /// <param name="slot">The binding slot.</param>
1291  /// <param name="buffer">The constant buffer to set.</param>
1292  internal void SetConstantBuffer(ShaderStage stage, int slot, Buffer buffer)
1293  {
1294 #if DEBUG
1295  EnsureContextActive();
1296 #endif
1297 
1298 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1299  // TODO: Dirty flags on both constant buffer content and if constant buffer changed
1300  if (stage != ShaderStage.Vertex || slot != 0)
1301  throw new InvalidOperationException("Only cbuffer slot 0 of vertex shader stage should be used on OpenGL ES 2.0.");
1302 
1303  constantBuffer = buffer;
1304 #else
1305  GL.BindBufferBase(BufferTarget.UniformBuffer, slot, buffer != null ? buffer.resourceId : 0);
1306 #endif
1307  }
1308 
1309  public void SetDepthStencilState(DepthStencilState depthStencilState, int stencilReference = 0)
1310  {
1311 #if DEBUG
1312  EnsureContextActive();
1313 #endif
1314 
1315  if (depthStencilState == null)
1316  depthStencilState = DepthStencilStates.Default;
1317 
1318  // Only apply a DepthStencilState if it is not already bound
1319  if (boundDepthStencilState != depthStencilState || boundStencilReference != stencilReference)
1320  {
1321  boundDepthStencilState = depthStencilState;
1322  boundStencilReference = stencilReference;
1323  boundDepthStencilState.Apply(stencilReference);
1324  }
1325  }
1326 
1327  public void SetRasterizerState(RasterizerState rasterizerState)
1328  {
1329 #if DEBUG
1330  EnsureContextActive();
1331 #endif
1332 
1333  if (rasterizerState == null)
1334  rasterizerState = RasterizerStates.CullBack;
1335 
1336  if (boundRasterizerState != rasterizerState)
1337  {
1338  boundRasterizerState = rasterizerState;
1339  boundRasterizerState.Apply();
1340  }
1341  }
1342 
1343  /// <summary>
1344  /// Sets a new depth stencil buffer and render target to this GraphicsDevice.
1345  /// </summary>
1346  /// <param name="depthStencilBuffer">The depth stencil buffer.</param>
1347  /// <param name="renderTarget">The render target.</param>
1348  public void SetRenderTarget(DepthStencilBuffer depthStencilBuffer, RenderTarget renderTarget)
1349  {
1350  SetRenderTargets(depthStencilBuffer, (renderTarget == null) ? null : new[] { renderTarget });
1351 
1352  if (renderTarget != null)
1353  {
1354  SetViewport(new Viewport(0, 0, renderTarget.Width, renderTarget.Height));
1355  }
1356  else if (depthStencilBuffer != null)
1357  {
1358  SetViewport(new Viewport(0, 0, depthStencilBuffer.Description.Width, depthStencilBuffer.Description.Height));
1359  }
1360  }
1361 
1362  public void SetRenderTargets(DepthStencilBuffer depthStencilBuffer, params RenderTarget[] renderTargets)
1363  {
1364  if (renderTargets == null)
1365  {
1366  throw new ArgumentNullException("renderTargets");
1367  }
1368 
1369  // ensure size is coherent
1370  var expectedWidth = renderTargets[0].Width;
1371  var expectedHeight = renderTargets[0].Height;
1372  if (depthStencilBuffer != null)
1373  {
1374  if (expectedWidth != depthStencilBuffer.Texture.Width || expectedHeight != depthStencilBuffer.Texture.Height)
1375  throw new Exception("Depth buffer is not the same size as the render target");
1376  }
1377  for (int i = 1; i < renderTargets.Length; ++i)
1378  {
1379  if (expectedWidth != renderTargets[i].Width || expectedHeight != renderTargets[i].Height)
1380  throw new Exception("Render targets do nt have the same size");
1381  }
1382 
1383  flipRenderTarget = true;
1384  foreach (var rt in renderTargets)
1385  {
1386  if (rt == BackBuffer)
1387  {
1388  flipRenderTarget = false;
1389  break;
1390  }
1391  }
1392 
1393 #if DEBUG
1394  EnsureContextActive();
1395 #endif
1396 
1397  for (int i = 0; i < renderTargets.Length; ++i)
1398  boundRenderTargets[i] = renderTargets[i];
1399  for (int i = renderTargets.Length; i < boundRenderTargets.Length; ++i)
1400  boundRenderTargets[i] = null;
1401 
1402  boundDepthStencilBuffer = depthStencilBuffer;
1403 
1404  needUpdateFBO = true;
1405 
1406  SetupTargets();
1407 
1408  var renderTarget = renderTargets.Length > 0 ? renderTargets[0] : null;
1409  if (renderTarget != null)
1410  {
1411  SetViewport(new Viewport(0, 0, renderTarget.Width, renderTarget.Height));
1412  }
1413  else if (depthStencilBuffer != null)
1414  {
1415  SetViewport(new Viewport(0, 0, depthStencilBuffer.Description.Width, depthStencilBuffer.Description.Height));
1416  }
1417  }
1418 
1419  /// <summary>
1420  /// Unbinds all depth-stencil buffer and render targets from the output-merger stage.
1421  /// </summary>
1422  public void ResetTargets()
1423  {
1424  for (int i = 0; i < boundRenderTargets.Length; ++i)
1425  boundRenderTargets[i] = null;
1426  }
1427 
1428  /// <summary>
1429  /// Sets a sampler state to the shader pipeline.
1430  /// </summary>
1431  /// <param name="stage">The shader stage.</param>
1432  /// <param name="slot">The binding slot.</param>
1433  /// <param name="samplerState">The sampler state to set.</param>
1434  public void SetSamplerState(ShaderStage stage, int slot, SamplerState samplerState)
1435  {
1436 #if DEBUG
1437  EnsureContextActive();
1438 #endif
1439 
1440  samplerStates[slot] = samplerState;
1441  }
1442 
1443  /// <summary>
1444  /// Binds a single scissor rectangle to the rasterizer stage.
1445  /// </summary>
1446  /// <param name="left">The left.</param>
1447  /// <param name="top">The top.</param>
1448  /// <param name="right">The right.</param>
1449  /// <param name="bottom">The bottom.</param>
1450  public void SetScissorRectangles(int left, int top, int right, int bottom)
1451  {
1452 #if DEBUG
1453  EnsureContextActive();
1454 #endif
1455  //TODO: verify the range of the values
1456  GL.Scissor(left, bottom, right-left, top-bottom);
1457  }
1458 
1459  /// <summary>
1460  /// Binds a set of scissor rectangles to the rasterizer stage.
1461  /// </summary>
1462  /// <param name="scissorRectangles">The set of scissor rectangles to bind.</param>
1463  public unsafe void SetScissorRectangles(params Rectangle[] scissorRectangles)
1464  {
1465 #if DEBUG
1466  EnsureContextActive();
1467 #endif
1468 
1469 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1470  throw new NotImplementedException();
1471 #else
1472  //TODO: verify the range of the values
1473  var rectangleValues = new int[4*scissorRectangles.Length];
1474 
1475  for (int i = 0; i < scissorRectangles.Length; ++i)
1476  {
1477  rectangleValues[4*i] = scissorRectangles[i].X;
1478  rectangleValues[4*i + 1] = scissorRectangles[i].Y;
1479  rectangleValues[4*i + 2] = scissorRectangles[i].Width;
1480  rectangleValues[4*i + 3] = scissorRectangles[i].Height;
1481  }
1482 
1483  GL.ScissorArray(0, scissorRectangles.Length, rectangleValues);
1484 #endif
1485  }
1486 
1487  /// <summary>
1488  /// Sets a shader resource view to the shader pipeline.
1489  /// </summary>
1490  /// <param name="stage">The shader stage.</param>
1491  /// <param name="slot">The binding slot.</param>
1492  /// <param name="shaderResourceView">The shader resource view.</param>
1493  internal void SetShaderResourceView(ShaderStage stage, int slot, GraphicsResource shaderResourceView)
1494  {
1495 #if DEBUG
1496  EnsureContextActive();
1497 #endif
1498  if (textures[slot] != shaderResourceView)
1499  {
1500  textures[slot] = shaderResourceView as Texture;
1501  }
1502  }
1503 
1504  /// <inheritdoc/>
1505  public void SetStreamTargets(params Buffer[] buffers)
1506  {
1507 #if DEBUG
1508  EnsureContextActive();
1509 #endif
1510 
1511  throw new NotImplementedException();
1512  }
1513 
1514  /// <summary>
1515  /// Sets an unordered access view to the shader pipeline.
1516  /// </summary>
1517  /// <param name="stage">The stage.</param>
1518  /// <param name="slot">The slot.</param>
1519  /// <param name="unorderedAccessView">The unordered access view.</param>
1520  /// <exception cref="System.ArgumentException">Invalid stage.;stage</exception>
1521  internal void SetUnorderedAccessView(ShaderStage stage, int slot, GraphicsResource unorderedAccessView)
1522  {
1523 #if DEBUG
1524  EnsureContextActive();
1525 #endif
1526 
1527  if (stage != ShaderStage.Compute)
1528  throw new ArgumentException("Invalid stage.", "stage");
1529 
1530  throw new NotImplementedException();
1531  }
1532 
1533  internal void SetupTargets()
1534  {
1535  if (needUpdateFBO)
1536  {
1537  boundFBO = FindOrCreateFBO(boundDepthStencilBuffer, boundRenderTargets);
1538  }
1539  GL.BindFramebuffer(FramebufferTarget.Framebuffer, boundFBO);
1540 
1541  UpdateHasRenderTarget();
1542  UpdateHasDepthStencilBuffer();
1543 
1544  // Update glViewport (new height)
1545  if (boundRenderTargets[0] != null)
1546  boundFBOHeight = (boundRenderTargets[0].Description).Height;
1547  else if (boundDepthStencilBuffer != null)
1548  boundFBOHeight = (boundDepthStencilBuffer.Description).Height;
1549  else
1550  boundFBOHeight = 0;
1551 
1552  UpdateViewport(_currentViewports[0]);
1553  }
1554 
1555  private void UpdateHasRenderTarget()
1556  {
1557  var hadRenderTarget = hasRenderTarget;
1558  hasRenderTarget = boundFBO != 0 || boundRenderTargets[0] != null;
1559 
1560  if (hasRenderTarget != hadRenderTarget)
1561  {
1562  var blendState = boundBlendState ?? BlendStates.Default;
1563  blendState.ApplyColorMask();
1564  }
1565  }
1566 
1567  private void UpdateHasDepthStencilBuffer()
1568  {
1569  var hadDepthStencilBuffer = hasDepthStencilBuffer;
1570  hasDepthStencilBuffer = boundFBO != 0 || boundDepthStencilBuffer != null;
1571 
1572  if (hasDepthStencilBuffer != hadDepthStencilBuffer)
1573  {
1574  var depthStencilState = boundDepthStencilState ?? DepthStencilStates.Default;
1575  depthStencilState.ApplyDepthMask();
1576  }
1577  }
1578 
1579  public void SetVertexArrayObject(VertexArrayObject vertexArrayObject)
1580  {
1581  currentVertexArrayObject = vertexArrayObject;
1582  }
1583 
1584  internal void UnbindVertexArrayObject()
1585  {
1586  boundVertexArrayObject = null;
1587  if (HasVAO)
1588  {
1589 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1590  OpenTK.Graphics.ES20.GL.Oes.BindVertexArray(0);
1591 #else
1592  GL.BindVertexArray(0);
1593 #endif
1594  }
1595 
1596  // Disable all vertex attribs
1597  int currentVertexAttribIndex = 0;
1598  while (enabledVertexAttribArrays != 0)
1599  {
1600  if ((enabledVertexAttribArrays & 1) == 1)
1601  {
1602  GL.DisableVertexAttribArray(currentVertexAttribIndex);
1603  }
1604 
1605  currentVertexAttribIndex++;
1606  enabledVertexAttribArrays >>= 1;
1607  }
1608  }
1609 
1610 
1611  /// <summary>
1612  /// Gets or sets the 1st viewport.
1613  /// </summary>
1614  /// <value>The viewport.</value>
1615  public void SetViewport(Viewport value)
1616  {
1617 #if DEBUG
1618  EnsureContextActive();
1619 #endif
1620 
1621  _currentViewports[0] = value;
1622  UpdateViewport(value);
1623  }
1624 
1625  public void SetViewport(int index, Viewport value)
1626  {
1627 #if DEBUG
1628  EnsureContextActive();
1629 #endif
1630 
1631 #if !SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1632  _currentViewports[index] = value;
1633  UpdateViewports();
1634 #endif
1635 
1636  throw new NotImplementedException();
1637  }
1638 
1639  internal int TryCompileShader(ShaderType shaderType, string sourceCode)
1640  {
1641  int shaderGL = GL.CreateShader(shaderType);
1642  GL.ShaderSource(shaderGL, sourceCode);
1643  GL.CompileShader(shaderGL);
1644 
1645  var log = GL.GetShaderInfoLog(shaderGL);
1646 
1647  int compileStatus;
1648  GL.GetShader(shaderGL, ShaderParameter.CompileStatus, out compileStatus);
1649 
1650  if (compileStatus != 1)
1651  throw new InvalidOperationException("Error while compiling GLSL shader: \n" + log);
1652 
1653  return shaderGL;
1654  }
1655 
1656  public void UnmapSubresource(MappedResource unmapped)
1657  {
1658 #if DEBUG
1659  EnsureContextActive();
1660 #endif
1661 
1662  var texture = unmapped.Resource as Texture;
1663  if (texture != null)
1664  {
1665  if (texture.Description.Usage != GraphicsResourceUsage.Staging)
1666  throw new NotSupportedException("Only staging textures can be mapped.");
1667 
1668 #if !SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1669  GL.BindBuffer(BufferTarget.PixelPackBuffer, texture.ResourceId);
1670  GL.UnmapBuffer(BufferTarget.PixelPackBuffer);
1671  GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
1672 #endif
1673  }
1674  else
1675  {
1676  var buffer = unmapped.Resource as Buffer;
1677  if (buffer != null)
1678  {
1679 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1680  // Only buffer with StagingData (fake cbuffer) could be mapped
1681  if (buffer.StagingData == null)
1682  throw new InvalidOperationException();
1683 
1684  // Is it a real buffer? (fake cbuffer have no real GPU counter-part in OpenGL ES 2.0
1685  if (buffer.ResourceId != 0)
1686  {
1687  UnbindVertexArrayObject();
1688  GL.BindBuffer(buffer.bufferTarget, buffer.ResourceId);
1689  GL.BufferSubData(buffer.bufferTarget, (IntPtr)unmapped.OffsetInBytes, (IntPtr)unmapped.SizeInBytes, unmapped.DataBox.DataPointer);
1690  GL.BindBuffer(buffer.bufferTarget, 0);
1691  }
1692 #else
1693  UnbindVertexArrayObject();
1694  GL.BindBuffer(buffer.bufferTarget, buffer.ResourceId);
1695  GL.UnmapBuffer(buffer.bufferTarget);
1696  GL.BindBuffer(buffer.bufferTarget, 0);
1697 #endif
1698  }
1699  else
1700  {
1701  throw new NotImplementedException();
1702  }
1703  }
1704  }
1705 
1706  public void UnsetReadWriteBuffers()
1707  {
1708 #if DEBUG
1709  EnsureContextActive();
1710 #endif
1711  }
1712 
1713  public void UnsetRenderTargets()
1714  {
1715 #if DEBUG
1716  EnsureContextActive();
1717 #endif
1718 
1719  SetRenderTargets((DepthStencilBuffer)null, null);
1720  }
1721 
1722  internal void UpdateSubresource(GraphicsResource resource, int subResourceIndex, DataBox databox)
1723  {
1724 #if DEBUG
1725  EnsureContextActive();
1726 #endif
1727  var buffer = resource as Buffer;
1728  if (buffer != null)
1729  {
1730 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1731  if (buffer.StagingData != IntPtr.Zero)
1732  {
1733  // Specific case for constant buffers
1734  SiliconStudio.Core.Utilities.CopyMemory(buffer.StagingData, databox.DataPointer, buffer.Description.SizeInBytes);
1735  return;
1736  }
1737 #endif
1738 
1739  UnbindVertexArrayObject();
1740 
1741  GL.BindBuffer(buffer.bufferTarget, buffer.ResourceId);
1742  GL.BufferData(buffer.bufferTarget, (IntPtr) buffer.Description.SizeInBytes, databox.DataPointer,
1743  buffer.bufferUsageHint);
1744  GL.BindBuffer(buffer.bufferTarget, 0);
1745  }
1746  else
1747  {
1748  var texture = resource as Texture;
1749  if (texture != null)
1750  {
1751  if (activeTexture != 0)
1752  {
1753  activeTexture = 0;
1754  GL.ActiveTexture(TextureUnit.Texture0);
1755  }
1756 
1757  // TODO: Handle pitchs
1758  var desc = texture.Description;
1759  GL.BindTexture(TextureTarget.Texture2D, texture.ResourceId);
1760  boundTextures[0] = null;
1761  GL.TexImage2D(TextureTarget.Texture2D, subResourceIndex, texture.InternalFormat, desc.Width, desc.Height, 0, texture.FormatGl, texture.Type, databox.DataPointer);
1762  }
1763  else
1764  {
1765  throw new NotImplementedException();
1766  }
1767  }
1768  }
1769 
1770  internal void UpdateSubresource(GraphicsResource resource, int subResourceIndex, DataBox databox, ResourceRegion region)
1771  {
1772 #if DEBUG
1773  EnsureContextActive();
1774 #endif
1775  var texture = resource as Texture;
1776 
1777  if (texture != null)
1778  {
1779  var width = region.Right - region.Left;
1780  var height = region.Bottom - region.Top;
1781 
1782  // determine the opengl read Unpack Alignment
1783  var packAlignment = 0;
1784  if ((databox.RowPitch & 1) != 0)
1785  {
1786  if (databox.RowPitch == width)
1787  packAlignment = 1;
1788  }
1789  else if ((databox.RowPitch & 2) != 0)
1790  {
1791  var diff = databox.RowPitch - width;
1792  if (diff >= 0 && diff < 2)
1793  packAlignment = 2;
1794  }
1795  else if ((databox.RowPitch & 4) != 0)
1796  {
1797  var diff = databox.RowPitch - width;
1798  if (diff >= 0 && diff < 4)
1799  packAlignment = 4;
1800  }
1801  else if ((databox.RowPitch & 8) != 0)
1802  {
1803  var diff = databox.RowPitch - width;
1804  if (diff >= 0 && diff < 8)
1805  packAlignment = 8;
1806  }
1807  else if(databox.RowPitch == width)
1808  {
1809  packAlignment = 4;
1810  }
1811  if(packAlignment == 0)
1812  throw new NotImplementedException("The data box RowPitch is not compatible with the region width. This requires additional copy to be implemented.");
1813 
1814  // change the Unpack Alignment
1815  int previousPackAlignment;
1816  GL.GetInteger(GetPName.UnpackAlignment, out previousPackAlignment);
1817  GL.PixelStore(PixelStoreParameter.UnpackAlignment, packAlignment);
1818 
1819  if (activeTexture != 0)
1820  {
1821  activeTexture = 0;
1822  GL.ActiveTexture(TextureUnit.Texture0);
1823  }
1824 
1825  // Update the texture region
1826  GL.BindTexture(texture.Target, texture.resourceId);
1827  GL.TexSubImage2D(texture.Target, subResourceIndex, region.Left, region.Top, width, height, texture.FormatGl, texture.Type, databox.DataPointer);
1828  boundTextures[0] = null;
1829 
1830  // reset the Unpack Alignment
1831  GL.PixelStore(PixelStoreParameter.UnpackAlignment, previousPackAlignment);
1832  }
1833  }
1834 
1835  internal static void UnbindGraphicsContext(IGraphicsContext graphicsContext)
1836  {
1837  graphicsContext.MakeCurrent(null);
1838 
1839 #if SILICONSTUDIO_PLATFORM_IOS
1840  // Seems like iPhoneOSGraphicsContext.MakeCurrent(null) doesn't remove current context
1841  // Let's do it manually
1842  MonoTouch.OpenGLES.EAGLContext.SetCurrentContext(null);
1843 #endif
1844  }
1845 
1846  private void OnApplicationPaused(object sender, EventArgs e)
1847  {
1848  // Block async resource creation
1849  Monitor.Enter(asyncCreationLockObject, ref asyncCreationLockTaken);
1850 
1851  ApplicationPaused = true;
1852 
1853  using (UseOpenGLCreationContext())
1854  {
1855  GL.Finish();
1856  }
1857 
1858  // Unset graphics context
1859  UnbindGraphicsContext(graphicsContext);
1860  }
1861 
1862  private void OnApplicationResumed(object sender, EventArgs e)
1863  {
1864  windowInfo = gameWindow.WindowInfo;
1865 
1866  // Reenable graphics context
1867  graphicsContext.MakeCurrent(windowInfo);
1868 
1869  ApplicationPaused = false;
1870 
1871  // Reenable async resource creation
1872  if (asyncCreationLockTaken)
1873  {
1874  Monitor.Exit(asyncCreationLockObject);
1875  asyncCreationLockTaken = false;
1876  }
1877  }
1878 
1879  internal void UpdateViewport(Viewport viewport)
1880  {
1881  GL.Viewport((int)viewport.X, boundFBOHeight - (int)viewport.Y - (int)viewport.Height, (int)viewport.Width, (int)viewport.Height);
1882  }
1883 
1884 #if !SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1885  internal void UpdateViewports()
1886  {
1887  int nbViewports = _currentViewports.Length;
1888  float[] viewports = new float[nbViewports * 4];
1889  for (int i = 0; i < nbViewports; ++i)
1890  {
1891  var currViewport = _currentViewports[i];
1892  viewports[4 * i] = currViewport.X;
1893  viewports[4 * i + 1] = currViewport.Height - currViewport.Y;
1894  viewports[4 * i + 2] = currViewport.Width;
1895  viewports[4 * i + 3] = currViewport.Height;
1896  }
1897  GL.ViewportArray(0, nbViewports, viewports);
1898  }
1899 #endif
1900 
1901  protected void InitializePlatformDevice(GraphicsProfile[] graphicsProfile, DeviceCreationFlags deviceCreationFlags, WindowHandle windowHandle)
1902  {
1903 #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
1904  gameWindow = (OpenTK.GameWindow)windowHandle.NativeHandle;
1905  graphicsContext = gameWindow.Context;
1906 #elif SILICONSTUDIO_PLATFORM_ANDROID
1907  // Force a reference to AndroidGameView from OpenTK 0.9, otherwise linking will fail in release mode for MonoDroid.
1908  typeof (opentkold::OpenTK.Platform.Android.AndroidGameView).ToString();
1909  gameWindow = (AndroidGameView)windowHandle.NativeHandle;
1910  graphicsContext = gameWindow.GraphicsContext;
1911  gameWindow.Load += OnApplicationResumed;
1912  gameWindow.Unload += OnApplicationPaused;
1913 #elif SILICONSTUDIO_PLATFORM_IOS
1914  gameWindow = (iPhoneOSGameView)windowHandle.NativeHandle;
1915  graphicsContext = gameWindow.GraphicsContext;
1916  gameWindow.Load += OnApplicationResumed;
1917  gameWindow.Unload += OnApplicationPaused;
1918 #endif
1919 
1920  windowInfo = gameWindow.WindowInfo;
1921 
1922  // Enable OpenGL context sharing
1923  GraphicsContext.ShareContexts = true;
1924 
1925  // TODO: How to control Debug flags?
1926  var creationFlags = GraphicsContextFlags.Default;
1927 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
1928  versionMajor = 2;
1929  versionMinor = 0;
1930 #if !SILICONSTUDIO_PLATFORM_MONO_MOBILE
1931  OpenTK.Platform.Utilities.ForceEmbedded = true;
1932 #endif
1933  creationFlags |= GraphicsContextFlags.Embedded;
1934 #else
1935  versionMajor = 4;
1936  versionMinor = 2;
1937 #endif
1938 
1939  // Doesn't seems to be working on Android
1940 #if SILICONSTUDIO_PLATFORM_ANDROID
1941  var renderer = GL.GetString(StringName.Renderer);
1942  Workaround_VAO_PowerVR_SGX_540 = renderer == "PowerVR SGX 540";
1943  Workaround_Context_Tegra2_Tegra3 = renderer == "NVIDIA Tegra 3" || renderer == "NVIDIA Tegra 2";
1944 
1945  var androidGraphicsContext = (AndroidGraphicsContext)graphicsContext;
1946  if (Workaround_Context_Tegra2_Tegra3)
1947  {
1948  // On Tegra2/Tegra3, we can't do any background context
1949  // As a result, we reuse main graphics context even when loading.
1950  // Of course, main graphics context need to be either available, or we register ourself for next ExecutePendingTasks().
1951  deviceCreationContext = graphicsContext;
1952  deviceCreationWindowInfo = windowInfo;
1953 
1954  // We don't want context to be set or it might collide with our internal use to create async resources
1955  gameWindow.AutoSetContextOnRenderFrame = false;
1956  }
1957  else
1958  {
1959  if (androidAsyncDeviceCreationContext != null)
1960  {
1961  androidAsyncDeviceCreationContext.Dispose();
1962  deviceCreationContext.Dispose();
1963  deviceCreationWindowInfo.Dispose();
1964  }
1965  androidAsyncDeviceCreationContext = new AndroidAsyncGraphicsContext(androidGraphicsContext, (AndroidWindow)windowInfo);
1966  deviceCreationContext = OpenTK.Graphics.GraphicsContext.CreateDummyContext(androidAsyncDeviceCreationContext.Context);
1967  deviceCreationWindowInfo = OpenTK.Platform.Utilities.CreateDummyWindowInfo();
1968  }
1969 
1970  graphicsContextEglPtr = EglGetCurrentContext();
1971 #elif SILICONSTUDIO_PLATFORM_IOS
1972  var asyncContext = new MonoTouch.OpenGLES.EAGLContext(MonoTouch.OpenGLES.EAGLRenderingAPI.OpenGLES2, gameWindow.EAGLContext.ShareGroup);
1973  MonoTouch.OpenGLES.EAGLContext.SetCurrentContext(asyncContext);
1974  deviceCreationContext = new OpenTK.Graphics.GraphicsContext(new OpenTK.ContextHandle(asyncContext.Handle), null, graphicsContext, versionMajor, versionMinor, creationFlags);
1975  deviceCreationWindowInfo = windowInfo;
1976  gameWindow.MakeCurrent();
1977 #else
1978  deviceCreationWindowInfo = windowInfo;
1979  deviceCreationContext = new GraphicsContext(graphicsContext.GraphicsMode, deviceCreationWindowInfo, versionMajor, versionMinor, creationFlags);
1980  GraphicsContext.CurrentContext.MakeCurrent(null);
1981 #endif
1982 
1983  // Create default OpenGL State objects
1984  defaultSamplerState = SamplerState.New(this, new SamplerStateDescription(TextureFilter.MinPointMagMipLinear, TextureAddressMode.Wrap) { MaxAnisotropy = 1 }).KeepAliveBy(this);
1985 
1986  this.immediateContext = this;
1987  }
1988 
1989  protected void DestroyPlatformDevice()
1990  {
1991  // Hack: Reset the lock so that UseOpenGLCreationContext works (even if locked by previously called OnApplicationPaused, which might have been done in an unaccessible event thread)
1992  // TODO: Does it work with Tegra3?
1993  if (ApplicationPaused)
1994  {
1995  asyncCreationLockObject = new object();
1996  }
1997 
1998 #if SILICONSTUDIO_PLATFORM_ANDROID || SILICONSTUDIO_PLATFORM_IOS
1999  gameWindow.Load -= OnApplicationResumed;
2000  gameWindow.Unload -= OnApplicationPaused;
2001 #endif
2002  }
2003 
2004  internal void OnDestroyed()
2005  {
2006  EffectInputSignature.OnDestroyed();
2007 
2008  // Clear existing FBOs
2009  lock (RootDevice.existingFBOs)
2010  {
2011  RootDevice.existingFBOs.Clear();
2012  RootDevice.existingFBOs[new FBOKey(windowProvidedDepthBuffer, new[] { windowProvidedRenderTarget })] = windowProvidedFrameBuffer;
2013  }
2014 
2015  // Clear bound states
2016  for (int i = 0; i < boundTextures.Length; ++i)
2017  boundTextures[i] = null;
2018 
2019  boundFrontFace = FrontFaceDirection.Ccw;
2020 
2021  boundVertexArrayObject = null;
2022  enabledVertexAttribArrays = 0;
2023  boundDepthStencilState = null;
2024  boundStencilReference = 0;
2025  boundBlendState = null;
2026  boundRasterizerState = null;
2027  boundDepthStencilBuffer = null;
2028 
2029  for (int i = 0; i < boundRenderTargets.Length; ++i)
2030  boundRenderTargets[i] = null;
2031 
2032  boundFBO = 0;
2033  boundFBOHeight = 0;
2034  boundProgram = 0;
2035  }
2036 
2037  private void SetDefaultStates()
2038  {
2039  Begin();
2040  SetDepthStencilState(null);
2041  currentFrontFace = FrontFaceDirection.Cw;
2042  boundFrontFace = FrontFaceDirection.Cw;
2043  GL.FrontFace(currentFrontFace);
2044  End();
2045  }
2046 
2047  internal void InitDefaultRenderTarget(PresentationParameters presentationParameters)
2048  {
2049  // TODO: iOS (and possibly other platforms): get real render buffer ID for color/depth?
2050  windowProvidedRenderTexture = new Texture2D(this, new TextureDescription
2051  {
2052  Dimension = TextureDimension.Texture2D,
2053  Format = presentationParameters.BackBufferFormat,
2054  Width = presentationParameters.BackBufferWidth,
2055  Height = presentationParameters.BackBufferHeight,
2056  Flags = TextureFlags.RenderTarget,
2057  Depth = 1,
2058  MipLevels = 1,
2059  ArraySize = 1
2060  }, null, false);
2061  windowProvidedRenderTexture.Reload = (graphicsResource) => { };
2062  windowProvidedRenderTarget = windowProvidedRenderTexture.ToRenderTarget();
2063 
2064  if (presentationParameters.DepthStencilFormat != PixelFormat.None)
2065  {
2066  windowProvidedDepthTexture = new Texture2D(this, new TextureDescription
2067  {
2068  Dimension = TextureDimension.Texture2D,
2069  Format = presentationParameters.DepthStencilFormat,
2070  Width = presentationParameters.BackBufferWidth,
2071  Height = presentationParameters.BackBufferHeight,
2072  Flags = TextureFlags.DepthStencil,
2073  Depth = 1,
2074  MipLevels = 1,
2075  ArraySize = 1
2076  }, null, false);
2077  windowProvidedDepthTexture.Reload = (graphicsResource) => { };
2078  windowProvidedDepthBuffer = new DepthStencilBuffer(this, windowProvidedDepthTexture, false);
2079  }
2080 
2081 #if SILICONSTUDIO_PLATFORM_IOS
2082  // TODO: This can probably be valid for Android/PC as well (everything 0)
2083  windowProvidedFrameBuffer = gameWindow.Framebuffer;
2084  boundFBO = windowProvidedFrameBuffer;
2085 
2086  GL.BindFramebuffer(FramebufferTarget.Framebuffer, windowProvidedFrameBuffer);
2087 
2088  // Extract FBO render target
2089  int renderTargetTextureId;
2090  GL.GetFramebufferAttachmentParameter(FramebufferTarget.Framebuffer, FramebufferSlot.ColorAttachment0, FramebufferParameterName.FramebufferAttachmentObjectName, out renderTargetTextureId);
2091  windowProvidedRenderTexture.resourceId = renderTargetTextureId;
2092  windowProvidedRenderTexture.Reload = (graphicsResource) => { throw new NotImplementedException(); };
2093  windowProvidedRenderTarget.resourceId = renderTargetTextureId;
2094 
2095  // Extract FBO depth target
2096  GL.GetFramebufferAttachmentParameter(FramebufferTarget.Framebuffer, FramebufferSlot.DepthAttachment, FramebufferParameterName.FramebufferAttachmentObjectName, out renderTargetTextureId);
2097  windowProvidedDepthTexture.resourceId = renderTargetTextureId;
2098  windowProvidedDepthTexture.Reload = (graphicsResource) => { throw new NotImplementedException(); };
2099  windowProvidedDepthBuffer.resourceId = renderTargetTextureId;
2100 #endif
2101 
2102  RootDevice.existingFBOs[new FBOKey(windowProvidedDepthBuffer, new[] { windowProvidedRenderTarget })] = windowProvidedFrameBuffer;
2103 
2104  // TODO: Provide some flags to choose user prefers either:
2105  // - Auto-Blitting while allowing default RenderTarget to be associable with any DepthStencil
2106  // - No blitting, but default RenderTarget won't work with a custom FBO
2107  // - Later we should be able to detect that automatically?
2108  //defaultRenderTarget = Texture2D.New(this, presentationParameters.BackBufferWidth, presentationParameters.BackBufferHeight, PixelFormat.R8G8B8A8_UNorm, TextureFlags.ShaderResource | TextureFlags.RenderTarget).ToRenderTarget();
2109  defaultRenderTarget = windowProvidedRenderTarget;
2110  }
2111 
2112  public GraphicsDevice ImmediateContext
2113  {
2114  get { return this.immediateContext; }
2115  }
2116 
2117  public bool IsDeferredContextSupported
2118  {
2119  get { return false; }
2120  }
2121 
2122  private class SwapChainBackend
2123  {
2124  public PresentationParameters PresentationParameters;
2125  public int PresentCount;
2126  }
2127 
2128  /// <summary>
2129  /// Creates a swap chain from presentation parameters.
2130  /// </summary>
2131  /// <param name="presentationParameters">The presentation parameters.</param>
2132  /// <returns></returns>
2133  SwapChainBackend CreateSwapChainBackend(PresentationParameters presentationParameters)
2134  {
2135  var swapChainBackend = new SwapChainBackend();
2136  return swapChainBackend;
2137  }
2138 
2139  /// <summary>
2140  /// Gets the default presentation parameters associated with this graphics device.
2141  /// </summary>
2142  public PresentationParameters PresentationParameters
2143  {
2144  get
2145  {
2146  if (_defaultSwapChainBackend == null) throw new InvalidOperationException(FrameworkResources.NoDefaultRenterTarget);
2147  return _defaultSwapChainBackend.PresentationParameters;
2148  }
2149  }
2150 
2151  /// <summary>
2152  /// Gets the default render target associated with this graphics device.
2153  /// </summary>
2154  /// <value>The default render target.</value>
2155  internal RenderTarget DefaultRenderTarget
2156  {
2157  get
2158  {
2159  return defaultRenderTarget;
2160  }
2161  }
2162 
2163  /// <summary>
2164  /// Presents the display with the contents of the next buffer in the sequence of back buffers owned by the GraphicsDevice.
2165  /// </summary>
2166  /*public void Present()
2167  {
2168  ImmediateContext.Copy(DefaultRenderTarget.Texture, windowProvidedRenderTarget.Texture);
2169 #if SILICONSTUDIO_PLATFORM_ANDROID
2170  ((AndroidGraphicsContext)graphicsContext).Swap();
2171 #else
2172  GraphicsContext.CurrentContext.SwapBuffers();
2173 #endif
2174  //throw new NotImplementedException();
2175  }*/
2176 
2177  /// <summary>
2178  /// Gets or sets a value indicating whether this GraphicsDevice is in fullscreen.
2179  /// </summary>
2180  /// <value>
2181  /// <c>true</c> if this GraphicsDevice is fullscreen; otherwise, <c>false</c>.
2182  /// </value>
2183  public bool IsFullScreen
2184  {
2185  get
2186  {
2187  throw new NotImplementedException();
2188  }
2189 
2190  set
2191  {
2192  throw new NotImplementedException();
2193  }
2194  }
2195 
2196  // Notify render state that we used first texture and that it needs to be bound again
2197  internal void UseTemporaryFirstTexture()
2198  {
2199  activeTexture = 0;
2200  GL.ActiveTexture(TextureUnit.Texture0);
2201  boundTextures[0] = null;
2202  }
2203 
2204 #if SILICONSTUDIO_PLATFORM_ANDROID
2205  // Execute pending asynchronous object creation
2206  // (on android devices where we can't create background context such as Tegra2/Tegra3)
2207  internal void ExecutePendingTasks()
2208  {
2209  // Unbind context
2210  graphicsContext.MakeCurrent(null);
2211 
2212  // Release and reacquire lock
2213  Monitor.Wait(asyncCreationLockObject);
2214 
2215  // Rebind context
2216  graphicsContext.MakeCurrent(windowInfo);
2217  }
2218 #endif
2219 
2220  internal struct FBOKey
2221  {
2222  public readonly DepthStencilBuffer DepthStencilBuffer;
2223  public readonly RenderTarget[] RenderTargets;
2224  public readonly int LastRenderTarget;
2225 
2226  public FBOKey(DepthStencilBuffer depthStencilBuffer, RenderTarget[] renderTargets)
2227  {
2228  DepthStencilBuffer = depthStencilBuffer;
2229 
2230  LastRenderTarget = 0;
2231  if (renderTargets != null)
2232  {
2233  for (int i = 0; i < renderTargets.Length; ++i)
2234  {
2235  if (renderTargets[i] != null)
2236  {
2237  LastRenderTarget = i + 1;
2238  break;
2239  }
2240  }
2241  }
2242 
2243  RenderTargets = LastRenderTarget != 0 ? renderTargets : null;
2244  }
2245 
2246  public override bool Equals(object obj)
2247  {
2248  if (!(obj is FBOKey)) return false;
2249 
2250  var obj2 = (FBOKey)obj;
2251 
2252  if (obj2.DepthStencilBuffer != DepthStencilBuffer) return false;
2253 
2254  // Should have same number of render targets
2255  if (LastRenderTarget != obj2.LastRenderTarget)
2256  return false;
2257 
2258  // Since both object have same LastRenderTarget, array is valid at least until this spot.
2259  for (int i = 0; i < LastRenderTarget; ++i)
2260  if (obj2.RenderTargets[i] != RenderTargets[i])
2261  return false;
2262 
2263  return true;
2264  }
2265 
2266  public override int GetHashCode()
2267  {
2268  var result = DepthStencilBuffer != null ? DepthStencilBuffer.GetHashCode() : 0;
2269  if (RenderTargets != null)
2270  {
2271  for (int index = 0; index < LastRenderTarget; index++)
2272  {
2273  var renderTarget = RenderTargets[index];
2274  result ^= renderTarget != null ? renderTarget.GetHashCode() : 0;
2275  }
2276  }
2277  return result;
2278  }
2279  }
2280  }
2281 }
2282 
2283 #endif
SiliconStudio.Paradox.Games.Mathematics.Vector2 Vector2
GraphicsDeviceStatus
Describes the current status of a GraphicsDevice.
GraphicsResourceUsage
Identifies expected resource use during rendering. The usage directly reflects whether a resource is ...
TextureAddressMode
Identify a technique for resolving texture coordinates that are outside of the boundaries of a textur...
TextureFilter
Filtering options during texture sampling.
Represents a color in the form of rgba.
Definition: Color4.cs:42
SiliconStudio.Paradox.Graphics.Buffer Buffer
Definition: BasicEffect.cs:15
Flags
Enumeration of the new Assimp's flags.
SiliconStudio.Core.Mathematics.Color Color
Definition: ColorPicker.cs:14
Same as Deferred mode, except sprites are sorted by texture prior to drawing. This can improve perfor...
System.Windows.Shapes.Rectangle Rectangle
Definition: ColorPicker.cs:16
ShaderStage
Enum to specify shader stage.
Definition: ShaderStage.cs:12
SiliconStudio.Paradox.Graphics.PrimitiveType PrimitiveType
Creates a render target buffer.
MapMode
Describes how the cpu is accessing a GraphicsResource with the GraphicsDeviceContext.Map method.
Definition: MapMode.cs:8
Blend
Blend option. A blend option identifies the data source and an optional pre-blend operation...
Definition: Blend.cs:14
GraphicsProfile
Identifies the set of supported devices for the demo based on device capabilities.
PixelFormat
Defines various types of pixel formats.
Definition: PixelFormat.cs:32
DepthStencilClearOptions
Specifies the buffer to use when calling Clear.
The texture dimension is 2D.