TextureView.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. using OpenTK.Graphics.OpenGL;
  2. using Ryujinx.Common;
  3. using Ryujinx.Graphics.GAL;
  4. using System;
  5. namespace Ryujinx.Graphics.OpenGL.Image
  6. {
  7. class TextureView : TextureBase, ITexture, ITextureInfo
  8. {
  9. private readonly OpenGLRenderer _renderer;
  10. private readonly TextureStorage _parent;
  11. public ITextureInfo Storage => _parent;
  12. public int FirstLayer { get; private set; }
  13. public int FirstLevel { get; private set; }
  14. public TextureView(
  15. OpenGLRenderer renderer,
  16. TextureStorage parent,
  17. TextureCreateInfo info,
  18. int firstLayer,
  19. int firstLevel) : base(info, parent.ScaleFactor)
  20. {
  21. _renderer = renderer;
  22. _parent = parent;
  23. FirstLayer = firstLayer;
  24. FirstLevel = firstLevel;
  25. CreateView();
  26. }
  27. private void CreateView()
  28. {
  29. TextureTarget target = Target.Convert();
  30. FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
  31. PixelInternalFormat pixelInternalFormat;
  32. if (format.IsCompressed)
  33. {
  34. pixelInternalFormat = (PixelInternalFormat)format.PixelFormat;
  35. }
  36. else
  37. {
  38. pixelInternalFormat = format.PixelInternalFormat;
  39. }
  40. int levels = Info.GetLevelsClamped();
  41. GL.TextureView(
  42. Handle,
  43. target,
  44. _parent.Handle,
  45. pixelInternalFormat,
  46. FirstLevel,
  47. levels,
  48. FirstLayer,
  49. Info.GetLayers());
  50. GL.ActiveTexture(TextureUnit.Texture0);
  51. GL.BindTexture(target, Handle);
  52. int[] swizzleRgba = new int[]
  53. {
  54. (int)Info.SwizzleR.Convert(),
  55. (int)Info.SwizzleG.Convert(),
  56. (int)Info.SwizzleB.Convert(),
  57. (int)Info.SwizzleA.Convert()
  58. };
  59. if (Info.Format == Format.A1B5G5R5Unorm)
  60. {
  61. int temp = swizzleRgba[0];
  62. int temp2 = swizzleRgba[1];
  63. swizzleRgba[0] = swizzleRgba[3];
  64. swizzleRgba[1] = swizzleRgba[2];
  65. swizzleRgba[2] = temp2;
  66. swizzleRgba[3] = temp;
  67. }
  68. else if (Info.Format.IsBgr())
  69. {
  70. // Swap B <-> R for BGRA formats, as OpenGL has no support for them
  71. // and we need to manually swap the components on read/write on the GPU.
  72. int temp = swizzleRgba[0];
  73. swizzleRgba[0] = swizzleRgba[2];
  74. swizzleRgba[2] = temp;
  75. }
  76. GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba);
  77. int maxLevel = levels - 1;
  78. if (maxLevel < 0)
  79. {
  80. maxLevel = 0;
  81. }
  82. GL.TexParameter(target, TextureParameterName.TextureMaxLevel, maxLevel);
  83. GL.TexParameter(target, TextureParameterName.DepthStencilTextureMode, (int)Info.DepthStencilMode.Convert());
  84. }
  85. public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
  86. {
  87. firstLayer += FirstLayer;
  88. firstLevel += FirstLevel;
  89. return _parent.CreateView(info, firstLayer, firstLevel);
  90. }
  91. public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
  92. {
  93. TextureView destinationView = (TextureView)destination;
  94. if (destinationView.Target.IsMultisample() || Target.IsMultisample())
  95. {
  96. Extents2D srcRegion = new Extents2D(0, 0, Width, Height);
  97. Extents2D dstRegion = new Extents2D(0, 0, destinationView.Width, destinationView.Height);
  98. TextureView intermmediate = _renderer.TextureCopy.IntermmediatePool.GetOrCreateWithAtLeast(
  99. GetIntermmediateTarget(Target),
  100. Info.BlockWidth,
  101. Info.BlockHeight,
  102. Info.BytesPerPixel,
  103. Format,
  104. Width,
  105. Height,
  106. Info.Depth,
  107. Info.Levels);
  108. GL.Disable(EnableCap.FramebufferSrgb);
  109. _renderer.TextureCopy.Copy(this, intermmediate, srcRegion, srcRegion, true);
  110. _renderer.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, true, 0, firstLayer, 0, firstLevel);
  111. GL.Enable(EnableCap.FramebufferSrgb);
  112. }
  113. else
  114. {
  115. _renderer.TextureCopy.CopyUnscaled(this, destinationView, 0, firstLayer, 0, firstLevel);
  116. }
  117. }
  118. public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
  119. {
  120. TextureView destinationView = (TextureView)destination;
  121. if (destinationView.Target.IsMultisample() || Target.IsMultisample())
  122. {
  123. Extents2D srcRegion = new Extents2D(0, 0, Width, Height);
  124. Extents2D dstRegion = new Extents2D(0, 0, destinationView.Width, destinationView.Height);
  125. TextureView intermmediate = _renderer.TextureCopy.IntermmediatePool.GetOrCreateWithAtLeast(
  126. GetIntermmediateTarget(Target),
  127. Info.BlockWidth,
  128. Info.BlockHeight,
  129. Info.BytesPerPixel,
  130. Format,
  131. Math.Max(1, Width >> srcLevel),
  132. Math.Max(1, Height >> srcLevel),
  133. 1,
  134. 1);
  135. GL.Disable(EnableCap.FramebufferSrgb);
  136. _renderer.TextureCopy.Copy(this, intermmediate, srcRegion, srcRegion, true, srcLayer, 0, srcLevel, 0, 1, 1);
  137. _renderer.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, true, 0, dstLayer, 0, dstLevel, 1, 1);
  138. GL.Enable(EnableCap.FramebufferSrgb);
  139. }
  140. else
  141. {
  142. _renderer.TextureCopy.CopyUnscaled(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
  143. }
  144. }
  145. private static Target GetIntermmediateTarget(Target srcTarget)
  146. {
  147. return srcTarget switch
  148. {
  149. Target.Texture2D => Target.Texture2DMultisample,
  150. Target.Texture2DArray => Target.Texture2DMultisampleArray,
  151. Target.Texture2DMultisampleArray => Target.Texture2DArray,
  152. _ => Target.Texture2D
  153. };
  154. }
  155. public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
  156. {
  157. _renderer.TextureCopy.Copy(this, (TextureView)destination, srcRegion, dstRegion, linearFilter);
  158. }
  159. public unsafe ReadOnlySpan<byte> GetData()
  160. {
  161. int size = 0;
  162. int levels = Info.GetLevelsClamped();
  163. for (int level = 0; level < levels; level++)
  164. {
  165. size += Info.GetMipSize(level);
  166. }
  167. ReadOnlySpan<byte> data;
  168. if (HwCapabilities.UsePersistentBufferForFlush)
  169. {
  170. data = _renderer.PersistentBuffers.Default.GetTextureData(this, size);
  171. }
  172. else
  173. {
  174. IntPtr target = _renderer.PersistentBuffers.Default.GetHostArray(size);
  175. WriteTo(target);
  176. data = new ReadOnlySpan<byte>(target.ToPointer(), size);
  177. }
  178. if (Format == Format.S8UintD24Unorm)
  179. {
  180. data = FormatConverter.ConvertD24S8ToS8D24(data);
  181. }
  182. return data;
  183. }
  184. public unsafe ReadOnlySpan<byte> GetData(int layer, int level)
  185. {
  186. int size = Info.GetMipSize(level);
  187. if (HwCapabilities.UsePersistentBufferForFlush)
  188. {
  189. return _renderer.PersistentBuffers.Default.GetTextureData(this, size, layer, level);
  190. }
  191. else
  192. {
  193. IntPtr target = _renderer.PersistentBuffers.Default.GetHostArray(size);
  194. int offset = WriteTo2D(target, layer, level);
  195. return new ReadOnlySpan<byte>(target.ToPointer(), size).Slice(offset);
  196. }
  197. }
  198. public void WriteToPbo(int offset, bool forceBgra)
  199. {
  200. WriteTo(IntPtr.Zero + offset, forceBgra);
  201. }
  202. public int WriteToPbo2D(int offset, int layer, int level)
  203. {
  204. return WriteTo2D(IntPtr.Zero + offset, layer, level);
  205. }
  206. private int WriteTo2D(IntPtr data, int layer, int level)
  207. {
  208. TextureTarget target = Target.Convert();
  209. Bind(target, 0);
  210. FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
  211. PixelFormat pixelFormat = format.PixelFormat;
  212. PixelType pixelType = format.PixelType;
  213. if (target == TextureTarget.TextureCubeMap || target == TextureTarget.TextureCubeMapArray)
  214. {
  215. target = TextureTarget.TextureCubeMapPositiveX + (layer % 6);
  216. }
  217. int mipSize = Info.GetMipSize2D(level);
  218. if (format.IsCompressed)
  219. {
  220. GL.GetCompressedTextureSubImage(Handle, level, 0, 0, layer, Math.Max(1, Info.Width >> level), Math.Max(1, Info.Height >> level), 1, mipSize, data);
  221. }
  222. else if (format.PixelFormat != PixelFormat.DepthStencil)
  223. {
  224. GL.GetTextureSubImage(Handle, level, 0, 0, layer, Math.Max(1, Info.Width >> level), Math.Max(1, Info.Height >> level), 1, pixelFormat, pixelType, mipSize, data);
  225. }
  226. else
  227. {
  228. GL.GetTexImage(target, level, pixelFormat, pixelType, data);
  229. // The GL function returns all layers. Must return the offset of the layer we're interested in.
  230. return target switch
  231. {
  232. TextureTarget.TextureCubeMapArray => (layer / 6) * mipSize,
  233. TextureTarget.Texture1DArray => layer * mipSize,
  234. TextureTarget.Texture2DArray => layer * mipSize,
  235. _ => 0
  236. };
  237. }
  238. return 0;
  239. }
  240. private void WriteTo(IntPtr data, bool forceBgra = false)
  241. {
  242. TextureTarget target = Target.Convert();
  243. Bind(target, 0);
  244. FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
  245. PixelFormat pixelFormat = format.PixelFormat;
  246. PixelType pixelType = format.PixelType;
  247. if (forceBgra)
  248. {
  249. if (pixelType == PixelType.UnsignedShort565)
  250. {
  251. pixelType = PixelType.UnsignedShort565Reversed;
  252. }
  253. else if (pixelType == PixelType.UnsignedShort565Reversed)
  254. {
  255. pixelType = PixelType.UnsignedShort565;
  256. }
  257. else
  258. {
  259. pixelFormat = PixelFormat.Bgra;
  260. }
  261. }
  262. int faces = 1;
  263. if (target == TextureTarget.TextureCubeMap)
  264. {
  265. target = TextureTarget.TextureCubeMapPositiveX;
  266. faces = 6;
  267. }
  268. int levels = Info.GetLevelsClamped();
  269. for (int level = 0; level < levels; level++)
  270. {
  271. for (int face = 0; face < faces; face++)
  272. {
  273. int faceOffset = face * Info.GetMipSize2D(level);
  274. if (format.IsCompressed)
  275. {
  276. GL.GetCompressedTexImage(target + face, level, data + faceOffset);
  277. }
  278. else
  279. {
  280. GL.GetTexImage(target + face, level, pixelFormat, pixelType, data + faceOffset);
  281. }
  282. }
  283. data += Info.GetMipSize(level);
  284. }
  285. }
  286. public void SetData(ReadOnlySpan<byte> data)
  287. {
  288. if (Format == Format.S8UintD24Unorm)
  289. {
  290. data = FormatConverter.ConvertS8D24ToD24S8(data);
  291. }
  292. unsafe
  293. {
  294. fixed (byte* ptr = data)
  295. {
  296. ReadFrom((IntPtr)ptr, data.Length);
  297. }
  298. }
  299. }
  300. public void SetData(ReadOnlySpan<byte> data, int layer, int level)
  301. {
  302. if (Format == Format.S8UintD24Unorm)
  303. {
  304. data = FormatConverter.ConvertS8D24ToD24S8(data);
  305. }
  306. unsafe
  307. {
  308. fixed (byte* ptr = data)
  309. {
  310. int width = Math.Max(Info.Width >> level, 1);
  311. int height = Math.Max(Info.Height >> level, 1);
  312. ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height);
  313. }
  314. }
  315. }
  316. public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
  317. {
  318. if (Format == Format.S8UintD24Unorm)
  319. {
  320. data = FormatConverter.ConvertS8D24ToD24S8(data);
  321. }
  322. int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
  323. int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight);
  324. unsafe
  325. {
  326. fixed (byte* ptr = data)
  327. {
  328. ReadFrom2D(
  329. (IntPtr)ptr,
  330. layer,
  331. level,
  332. region.X,
  333. region.Y,
  334. region.Width,
  335. region.Height,
  336. BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks);
  337. }
  338. }
  339. }
  340. public void ReadFromPbo(int offset, int size)
  341. {
  342. ReadFrom(IntPtr.Zero + offset, size);
  343. }
  344. public void ReadFromPbo2D(int offset, int layer, int level, int width, int height)
  345. {
  346. ReadFrom2D(IntPtr.Zero + offset, layer, level, 0, 0, width, height);
  347. }
  348. private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height)
  349. {
  350. int mipSize = Info.GetMipSize2D(level);
  351. ReadFrom2D(data, layer, level, x, y, width, height, mipSize);
  352. }
  353. private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height, int mipSize)
  354. {
  355. TextureTarget target = Target.Convert();
  356. Bind(target, 0);
  357. FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
  358. switch (Target)
  359. {
  360. case Target.Texture1D:
  361. if (format.IsCompressed)
  362. {
  363. GL.CompressedTexSubImage1D(
  364. target,
  365. level,
  366. x,
  367. width,
  368. format.PixelFormat,
  369. mipSize,
  370. data);
  371. }
  372. else
  373. {
  374. GL.TexSubImage1D(
  375. target,
  376. level,
  377. x,
  378. width,
  379. format.PixelFormat,
  380. format.PixelType,
  381. data);
  382. }
  383. break;
  384. case Target.Texture1DArray:
  385. if (format.IsCompressed)
  386. {
  387. GL.CompressedTexSubImage2D(
  388. target,
  389. level,
  390. x,
  391. layer,
  392. width,
  393. 1,
  394. format.PixelFormat,
  395. mipSize,
  396. data);
  397. }
  398. else
  399. {
  400. GL.TexSubImage2D(
  401. target,
  402. level,
  403. x,
  404. layer,
  405. width,
  406. 1,
  407. format.PixelFormat,
  408. format.PixelType,
  409. data);
  410. }
  411. break;
  412. case Target.Texture2D:
  413. if (format.IsCompressed)
  414. {
  415. GL.CompressedTexSubImage2D(
  416. target,
  417. level,
  418. x,
  419. y,
  420. width,
  421. height,
  422. format.PixelFormat,
  423. mipSize,
  424. data);
  425. }
  426. else
  427. {
  428. GL.TexSubImage2D(
  429. target,
  430. level,
  431. x,
  432. y,
  433. width,
  434. height,
  435. format.PixelFormat,
  436. format.PixelType,
  437. data);
  438. }
  439. break;
  440. case Target.Texture2DArray:
  441. case Target.Texture3D:
  442. case Target.CubemapArray:
  443. if (format.IsCompressed)
  444. {
  445. GL.CompressedTexSubImage3D(
  446. target,
  447. level,
  448. x,
  449. y,
  450. layer,
  451. width,
  452. height,
  453. 1,
  454. format.PixelFormat,
  455. mipSize,
  456. data);
  457. }
  458. else
  459. {
  460. GL.TexSubImage3D(
  461. target,
  462. level,
  463. x,
  464. y,
  465. layer,
  466. width,
  467. height,
  468. 1,
  469. format.PixelFormat,
  470. format.PixelType,
  471. data);
  472. }
  473. break;
  474. case Target.Cubemap:
  475. if (format.IsCompressed)
  476. {
  477. GL.CompressedTexSubImage2D(
  478. TextureTarget.TextureCubeMapPositiveX + layer,
  479. level,
  480. x,
  481. y,
  482. width,
  483. height,
  484. format.PixelFormat,
  485. mipSize,
  486. data);
  487. }
  488. else
  489. {
  490. GL.TexSubImage2D(
  491. TextureTarget.TextureCubeMapPositiveX + layer,
  492. level,
  493. x,
  494. y,
  495. width,
  496. height,
  497. format.PixelFormat,
  498. format.PixelType,
  499. data);
  500. }
  501. break;
  502. }
  503. }
  504. private void ReadFrom(IntPtr data, int size)
  505. {
  506. TextureTarget target = Target.Convert();
  507. int baseLevel = 0;
  508. // glTexSubImage on cubemap views is broken on Intel, we have to use the storage instead.
  509. if (Target == Target.Cubemap && HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows)
  510. {
  511. GL.ActiveTexture(TextureUnit.Texture0);
  512. GL.BindTexture(target, Storage.Handle);
  513. baseLevel = FirstLevel;
  514. }
  515. else
  516. {
  517. Bind(target, 0);
  518. }
  519. FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
  520. int width = Info.Width;
  521. int height = Info.Height;
  522. int depth = Info.Depth;
  523. int levels = Info.GetLevelsClamped();
  524. int offset = 0;
  525. for (int level = 0; level < levels; level++)
  526. {
  527. int mipSize = Info.GetMipSize(level);
  528. int endOffset = offset + mipSize;
  529. if ((uint)endOffset > (uint)size)
  530. {
  531. return;
  532. }
  533. switch (Target)
  534. {
  535. case Target.Texture1D:
  536. if (format.IsCompressed)
  537. {
  538. GL.CompressedTexSubImage1D(
  539. target,
  540. level,
  541. 0,
  542. width,
  543. format.PixelFormat,
  544. mipSize,
  545. data);
  546. }
  547. else
  548. {
  549. GL.TexSubImage1D(
  550. target,
  551. level,
  552. 0,
  553. width,
  554. format.PixelFormat,
  555. format.PixelType,
  556. data);
  557. }
  558. break;
  559. case Target.Texture1DArray:
  560. case Target.Texture2D:
  561. if (format.IsCompressed)
  562. {
  563. GL.CompressedTexSubImage2D(
  564. target,
  565. level,
  566. 0,
  567. 0,
  568. width,
  569. height,
  570. format.PixelFormat,
  571. mipSize,
  572. data);
  573. }
  574. else
  575. {
  576. GL.TexSubImage2D(
  577. target,
  578. level,
  579. 0,
  580. 0,
  581. width,
  582. height,
  583. format.PixelFormat,
  584. format.PixelType,
  585. data);
  586. }
  587. break;
  588. case Target.Texture2DArray:
  589. case Target.Texture3D:
  590. case Target.CubemapArray:
  591. if (format.IsCompressed)
  592. {
  593. GL.CompressedTexSubImage3D(
  594. target,
  595. level,
  596. 0,
  597. 0,
  598. 0,
  599. width,
  600. height,
  601. depth,
  602. format.PixelFormat,
  603. mipSize,
  604. data);
  605. }
  606. else
  607. {
  608. GL.TexSubImage3D(
  609. target,
  610. level,
  611. 0,
  612. 0,
  613. 0,
  614. width,
  615. height,
  616. depth,
  617. format.PixelFormat,
  618. format.PixelType,
  619. data);
  620. }
  621. break;
  622. case Target.Cubemap:
  623. int faceOffset = 0;
  624. for (int face = 0; face < 6; face++, faceOffset += mipSize / 6)
  625. {
  626. if (format.IsCompressed)
  627. {
  628. GL.CompressedTexSubImage2D(
  629. TextureTarget.TextureCubeMapPositiveX + face,
  630. baseLevel + level,
  631. 0,
  632. 0,
  633. width,
  634. height,
  635. format.PixelFormat,
  636. mipSize / 6,
  637. data + faceOffset);
  638. }
  639. else
  640. {
  641. GL.TexSubImage2D(
  642. TextureTarget.TextureCubeMapPositiveX + face,
  643. baseLevel + level,
  644. 0,
  645. 0,
  646. width,
  647. height,
  648. format.PixelFormat,
  649. format.PixelType,
  650. data + faceOffset);
  651. }
  652. }
  653. break;
  654. }
  655. data += mipSize;
  656. offset += mipSize;
  657. width = Math.Max(1, width >> 1);
  658. height = Math.Max(1, height >> 1);
  659. if (Target == Target.Texture3D)
  660. {
  661. depth = Math.Max(1, depth >> 1);
  662. }
  663. }
  664. }
  665. public void SetStorage(BufferRange buffer)
  666. {
  667. throw new NotSupportedException();
  668. }
  669. private void DisposeHandles()
  670. {
  671. if (Handle != 0)
  672. {
  673. GL.DeleteTexture(Handle);
  674. Handle = 0;
  675. }
  676. }
  677. /// <summary>
  678. /// Release the view without necessarily disposing the parent if we are the default view.
  679. /// This allows it to be added to the resource pool and reused later.
  680. /// </summary>
  681. public void Release()
  682. {
  683. bool hadHandle = Handle != 0;
  684. if (_parent.DefaultView != this)
  685. {
  686. DisposeHandles();
  687. }
  688. if (hadHandle)
  689. {
  690. _parent.DecrementViewsCount();
  691. }
  692. }
  693. public void Dispose()
  694. {
  695. if (_parent.DefaultView == this)
  696. {
  697. // Remove the default view (us), so that the texture cannot be released to the cache.
  698. _parent.DeleteDefault();
  699. }
  700. Release();
  701. }
  702. }
  703. }