PipelineCache.hx 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. package h3d.impl;
  2. #if !js
  3. #if hl
  4. @:forward(setI32,setUI8,setUI16,getUI8,getUI16,getI32,setF32,getF32,sub)
  5. private abstract Bytes(hl.Bytes) from hl.Bytes to hl.Bytes {
  6. public function new(size) this = new hl.Bytes(size);
  7. public inline function compare( bytes : Bytes, size : Int ) {
  8. return this.compare(0, bytes, 0, size);
  9. }
  10. }
  11. #else
  12. @:forward(sub)
  13. private abstract Bytes(haxe.io.Bytes) from haxe.io.Bytes {
  14. public function new(size) {
  15. this = haxe.io.Bytes.alloc(size);
  16. }
  17. public inline function setI32(idx:Int,v:Int) {
  18. this.setInt32(idx, v);
  19. }
  20. public inline function setUI8(idx:Int,v:Int) {
  21. this.set(idx, v);
  22. }
  23. public inline function setUI16(idx:Int,v:Int) {
  24. this.setUInt16(idx, v);
  25. }
  26. public inline function getI32(idx:Int) {
  27. return this.getInt32(idx);
  28. }
  29. public inline function getUI8(idx:Int) {
  30. return this.get(idx);
  31. }
  32. public inline function getUI16(idx:Int) {
  33. return this.getUInt16(idx);
  34. }
  35. public function compare( bytes : Bytes, size : Int ) {
  36. var bytes : haxe.io.Bytes = cast bytes;
  37. for( i in 0...size ) {
  38. var d = this.get(i) - bytes.get(i);
  39. if( d != 0 ) return d;
  40. }
  41. return 0;
  42. }
  43. }
  44. #end
  45. @:generic class CachedPipeline<T> {
  46. public var bytes : Bytes;
  47. public var size : Int;
  48. public var pipeline : T;
  49. public function new() {
  50. }
  51. }
  52. @:forward(get,set)
  53. abstract PipelineCache<T>(Map<Int,#if hl hl.NativeArray #else Array #end<CachedPipeline<T>>>) {
  54. public function new() {
  55. this = new Map();
  56. }
  57. }
  58. class DepthProps {
  59. public var format : hxd.PixelFormat;
  60. public var bias : Single;
  61. public var slopeScaledBias : Single;
  62. public function new() {}
  63. }
  64. class PipelineBuilder {
  65. static inline var PSIGN_MATID = 0;
  66. static inline var PSIGN_COLOR_MASK = PSIGN_MATID + 4;
  67. static inline var PSIGN_DEPTH_BIAS = PSIGN_COLOR_MASK + 1;
  68. static inline var PSIGN_SLOPE_SCALED_DEPTH_BIAS = PSIGN_DEPTH_BIAS + 4;
  69. static inline var PSIGN_STENCIL_MASK = PSIGN_SLOPE_SCALED_DEPTH_BIAS + 4;
  70. static inline var PSIGN_STENCIL_OPS = PSIGN_STENCIL_MASK + 2;
  71. static inline var PSIGN_RENDER_TARGETS = PSIGN_STENCIL_OPS + 4;
  72. static inline var PSIGN_DEPTH_TARGET_FORMAT = PSIGN_RENDER_TARGETS + 8;
  73. static inline var PSIGN_LAYOUT = PSIGN_DEPTH_TARGET_FORMAT + 4;
  74. static inline var MAX_BUFFERS = 8;
  75. static inline var SHIFT_PER_BUFFER = #if js 2 #else 1 #end;
  76. static inline var PSIGN_SIZE = PSIGN_LAYOUT + (MAX_BUFFERS << SHIFT_PER_BUFFER);
  77. public var needFlush : Bool;
  78. var signature = new Bytes(64);
  79. var tmpDepth = new DepthProps();
  80. var tmpPass = new h3d.mat.Pass("");
  81. var tmpStencil = new h3d.mat.Stencil();
  82. #if hl
  83. var adlerOut = new Bytes(4);
  84. #end
  85. public function new() {
  86. if( PSIGN_SIZE > 64 ) throw "assert";
  87. setDepthBias(0, 0);
  88. }
  89. static function getRTBits( tex : h3d.mat.Texture ) {
  90. inline function mk(channels,format) {
  91. return ((format + 1) << 2) | (channels - 1);
  92. }
  93. return switch( tex.format ) {
  94. case R8: mk(1, 0);
  95. case RG8: mk(2, 0);
  96. case RGB8: mk(3, 0);
  97. case RGBA: mk(4, 0);
  98. case R16F: mk(1, 1);
  99. case RG16F: mk(2, 1);
  100. case RGB16F: mk(3, 1);
  101. case RGBA16F: mk(4, 1);
  102. case R32F: mk(1, 2);
  103. case RG32F: mk(2, 2);
  104. case RGB32F: mk(3, 2);
  105. case RGBA32F: mk(4, 2);
  106. case R16U: mk(1, 3);
  107. case RG16U: mk(2, 3);
  108. case RGB16U: mk(3, 3);
  109. case RGBA16U: mk(4, 3);
  110. case RG11B10UF: mk(2, 4);
  111. case RGB10A2: mk(3, 4);
  112. default: throw "Unsupported RT format "+tex.format;
  113. }
  114. }
  115. public inline function setShader( sh : hxsl.RuntimeShader ) {
  116. needFlush = sh.mode != Compute;
  117. }
  118. public function setDepthBias( depthBias : Float, slopeScaledBias : Float ) {
  119. signature.setF32(PSIGN_DEPTH_BIAS, depthBias);
  120. signature.setF32(PSIGN_SLOPE_SCALED_DEPTH_BIAS, slopeScaledBias);
  121. needFlush = true;
  122. }
  123. static function initFormats() {
  124. var fmt = [];
  125. for( f in ([Depth16,Depth24,Depth24Stencil8,Depth32] : Array<hxd.PixelFormat>) )
  126. fmt[f.getIndex()] = f;
  127. return fmt;
  128. }
  129. public function getDepthProps() {
  130. static var FORMATS = initFormats();
  131. var d = tmpDepth;
  132. d.format = FORMATS[signature.getI32(PSIGN_DEPTH_TARGET_FORMAT)];
  133. d.bias = signature.getF32(PSIGN_DEPTH_BIAS);
  134. d.slopeScaledBias = signature.getF32(PSIGN_SLOPE_SCALED_DEPTH_BIAS);
  135. return d;
  136. }
  137. public function setRenderTarget( tex : h3d.mat.Texture, depthEnabled : Bool ) {
  138. signature.setI32(PSIGN_RENDER_TARGETS, tex == null ? 0 : getRTBits(tex));
  139. signature.setI32(PSIGN_RENDER_TARGETS + 4, 0);
  140. var format = tex == null || !depthEnabled ? 0 : tex.depthBuffer.format.getIndex();
  141. signature.setI32(PSIGN_DEPTH_TARGET_FORMAT, format);
  142. needFlush = true;
  143. }
  144. public function getDepthEnabled() {
  145. return signature.getI32(PSIGN_DEPTH_TARGET_FORMAT) != 0;
  146. }
  147. public function setDepth( depth : h3d.mat.Texture ) {
  148. signature.setI32(PSIGN_RENDER_TARGETS, 0);
  149. signature.setI32(PSIGN_RENDER_TARGETS + 4, 0);
  150. signature.setI32(PSIGN_DEPTH_TARGET_FORMAT, depth.format.getIndex());
  151. needFlush = true;
  152. }
  153. public function setRenderTargets( textures : Array<h3d.mat.Texture>, depthEnabled : Bool ) {
  154. var bits = 0;
  155. for( i => t in textures )
  156. signature.setUI8(PSIGN_RENDER_TARGETS + i, getRTBits(t));
  157. for ( i in textures.length...8)
  158. signature.setUI8(PSIGN_RENDER_TARGETS + i, 0);
  159. var tex = textures[0];
  160. var format = tex == null || !depthEnabled ? 0 : tex.depthBuffer.format.getIndex();
  161. signature.setI32(PSIGN_DEPTH_TARGET_FORMAT, format);
  162. needFlush = true;
  163. }
  164. public function selectMaterial( pass : h3d.mat.Pass ) @:privateAccess {
  165. signature.setI32(PSIGN_MATID, pass.bits);
  166. signature.setUI8(PSIGN_COLOR_MASK, pass.colorMask);
  167. var st = pass.stencil;
  168. if( st != null ) {
  169. signature.setUI16(PSIGN_STENCIL_MASK, st.maskBits & 0xFFFF);
  170. signature.setI32(PSIGN_STENCIL_OPS, st.opBits);
  171. } else {
  172. signature.setUI16(PSIGN_STENCIL_MASK, 0);
  173. signature.setI32(PSIGN_STENCIL_OPS, 0);
  174. }
  175. needFlush = true;
  176. }
  177. public inline function setBuffer( i : Int, inf : hxd.BufferFormat.BufferMapping, stride : Int ) {
  178. if( inf.offset >= 256 ) throw "assert";
  179. signature.setUI16(PSIGN_LAYOUT + (i<<SHIFT_PER_BUFFER), (inf.offset << 1) | inf.precision.toInt());
  180. #if js
  181. signature.setUI16(PSIGN_LAYOUT + (i<<SHIFT_PER_BUFFER) + 2, stride);
  182. #end
  183. needFlush = true;
  184. }
  185. public function getCurrentPass() @:privateAccess {
  186. var pass = tmpPass;
  187. pass.loadBits(signature.getI32(PSIGN_MATID));
  188. pass.colorMask = signature.getUI8(PSIGN_COLOR_MASK);
  189. var mask = signature.getUI16(PSIGN_STENCIL_MASK);
  190. var ops = signature.getI32(PSIGN_STENCIL_OPS);
  191. if( ops == 0 )
  192. pass.stencil = null;
  193. else {
  194. pass.stencil = tmpStencil;
  195. pass.stencil.loadMaskBits(mask);
  196. pass.stencil.loadOpBits(ops);
  197. }
  198. return pass;
  199. }
  200. public function getBufferInput( i : Int ) {
  201. var b = signature.getUI16(PSIGN_LAYOUT + (i<<SHIFT_PER_BUFFER));
  202. return new hxd.BufferFormat.BufferMapping(i, (b >> 1) & ~3, @:privateAccess new hxd.BufferFormat.Precision(b & 7));
  203. }
  204. #if js
  205. public function getBufferStride( i : Int ) {
  206. return signature.getUI16(PSIGN_LAYOUT + (i << SHIFT_PER_BUFFER) + 2);
  207. }
  208. #end
  209. function hashSign( size : Int ) {
  210. #if hl
  211. adlerOut.setI32(0, 0);
  212. hl.Format.digest(adlerOut, signature, size, 3);
  213. return adlerOut.getI32(0);
  214. #else
  215. var tot = 0;
  216. for( i in 0...size>>2 )
  217. tot = (tot * 31 + signature.getI32(i<<2)) % 0x7FFFFFFF;
  218. switch( size & 3 ) {
  219. case 0:
  220. case 2: tot = (tot * 31 + signature.getUI16(size - 2)) % 0x7FFFFFFF;
  221. default: throw "assert";
  222. }
  223. return tot;
  224. #end
  225. }
  226. public function lookup<T>( cache : PipelineCache<T>, inputs : Int ) : CachedPipeline<T> {
  227. needFlush = false;
  228. var signatureSize = PSIGN_LAYOUT + (inputs << SHIFT_PER_BUFFER);
  229. var hash = hashSign(signatureSize);
  230. var pipes = cache.get(hash);
  231. if( pipes == null ) {
  232. pipes = #if hl new hl.NativeArray(1) #else [] #end;
  233. cache.set(hash, pipes);
  234. }
  235. var insert = -1;
  236. for( i in 0...pipes.length ) {
  237. var p = pipes[i];
  238. if( p == null ) {
  239. insert = i;
  240. break;
  241. }
  242. if( p.size == signatureSize && p.bytes.compare(signature, signatureSize) == 0 )
  243. return p;
  244. }
  245. if( insert < 0 ) {
  246. #if hl
  247. var pipes2 = new hl.NativeArray(pipes.length + 1);
  248. pipes2.blit(0, pipes, 0, insert);
  249. cache.set(hash, pipes2);
  250. pipes = pipes2;
  251. #else
  252. insert = pipes.length + 1;
  253. #end
  254. }
  255. var cp = new CachedPipeline<T>();
  256. cp.bytes = signature.sub(0, signatureSize);
  257. cp.size = signatureSize;
  258. pipes[insert] = cp;
  259. return cp;
  260. }
  261. }
  262. #end