Stage3dDriver.hx 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. package h3d.impl;
  2. import h3d.impl.Driver;
  3. import h3d.mat.Pass;
  4. import h3d.mat.Stencil;
  5. import h3d.mat.Data;
  6. #if flash
  7. @:allow(h3d.impl.Stage3dDriver)
  8. class VertexWrapper {
  9. var vbuf : flash.display3D.VertexBuffer3D;
  10. var written : Bool;
  11. var b : ManagedBuffer;
  12. function new(vbuf, b) {
  13. this.vbuf = vbuf;
  14. this.b = b;
  15. }
  16. function finalize( driver : Stage3dDriver ) {
  17. if( written ) return;
  18. written = true;
  19. // fill all the free positions that were unwritten with zeroes (necessary for flash)
  20. var f = @:privateAccess b.freeList;
  21. while( f != null ) {
  22. if( f.count > 0 ) {
  23. var mem : UInt = f.count * b.stride * 4;
  24. if( driver.empty.length < mem ) driver.empty.length = mem;
  25. driver.uploadVertexBytes(@:privateAccess b.vbuf, f.pos, f.count, haxe.io.Bytes.ofData(driver.empty), 0);
  26. }
  27. f = f.next;
  28. }
  29. }
  30. }
  31. private class CompiledShader {
  32. public var p : flash.display3D.Program3D;
  33. public var s : hxsl.RuntimeShader;
  34. public var stride : Int;
  35. public var bufferFormat : Int;
  36. public var inputs : InputNames;
  37. public var usedTextures : Array<Bool>;
  38. public function new(s) {
  39. this.s = s;
  40. stride = 0;
  41. bufferFormat = 0;
  42. usedTextures = [];
  43. }
  44. }
  45. class Stage3dDriver extends Driver {
  46. // standard profile was introduced with Flash14 but it causes problems with filters, only enable it for flash15+
  47. public static var PROFILE = #if flash15 cast "standard" #else flash.display3D.Context3DProfile.BASELINE #end;
  48. public static var SHADER_CACHE_PATH = null;
  49. var s3d : flash.display.Stage3D;
  50. var ctx : flash.display3D.Context3D;
  51. var onCreateCallback : Bool -> Void;
  52. var curMatBits : Int;
  53. var curStOpBits : Int;
  54. var curStMaskBits : Int;
  55. var defStencil : Stencil;
  56. var curShader : CompiledShader;
  57. var curBuffer : Buffer;
  58. var curManagedBuffer : ManagedBuffer;
  59. var curMultiBuffer : Array<Int>;
  60. var curAttributes : Int;
  61. var curTextures : Array<h3d.mat.Texture>;
  62. var curSamplerBits : Array<Int>;
  63. var renderTargets : Int;
  64. var antiAlias : Int;
  65. var width : Int;
  66. var height : Int;
  67. var enableDraw : Bool;
  68. var frame : Int;
  69. var programs : Map<Int, CompiledShader>;
  70. var isStandardMode : Bool;
  71. var flashVersion : Float;
  72. var tdisposed : Texture;
  73. var defaultDepth : h3d.mat.Texture;
  74. var curColorMask = -1;
  75. @:allow(h3d.impl.VertexWrapper)
  76. var empty : flash.utils.ByteArray;
  77. public function new(antiAlias=0) {
  78. var v = flash.system.Capabilities.version.split(" ")[1].split(",");
  79. flashVersion = Std.parseFloat(v[0] + "." + v[1]);
  80. empty = new flash.utils.ByteArray();
  81. s3d = flash.Lib.current.stage.stage3Ds[0];
  82. programs = new Map();
  83. this.antiAlias = antiAlias;
  84. curTextures = [];
  85. curSamplerBits = [];
  86. curMultiBuffer = [];
  87. defStencil = new Stencil();
  88. defaultDepth = new h3d.mat.Texture( -1, -1, Depth24Stencil8);
  89. }
  90. override function logImpl( str : String ) {
  91. flash.Lib.trace(str);
  92. }
  93. override function getDriverName(details:Bool) {
  94. return ctx == null ? "None" : (details ? ctx.driverInfo : ctx.driverInfo.split(" ")[0]);
  95. }
  96. override function begin( frame : Int ) {
  97. reset();
  98. this.frame = frame;
  99. }
  100. function reset() {
  101. enableDraw = true;
  102. curMatBits = -1;
  103. curStOpBits = -1;
  104. curStMaskBits = -1;
  105. curShader = null;
  106. curBuffer = null;
  107. curMultiBuffer[0] = -1;
  108. for( i in 0...curAttributes )
  109. ctx.setVertexBufferAt(i, null);
  110. curAttributes = 0;
  111. for( i in 0...curTextures.length ) {
  112. ctx.setTextureAt(i, null);
  113. curTextures[i] = null;
  114. }
  115. for( i in 0...curSamplerBits.length )
  116. curSamplerBits[i] = -1;
  117. }
  118. override function init( onCreate, forceSoftware = false ) {
  119. isStandardMode = Std.string(PROFILE) == "standard";
  120. if( isStandardMode && flashVersion < 14 ) {
  121. isStandardMode = false;
  122. PROFILE = flash.display3D.Context3DProfile.BASELINE;
  123. }
  124. this.onCreateCallback = onCreate;
  125. s3d.addEventListener(flash.events.Event.CONTEXT3D_CREATE, this.onCreate);
  126. s3d.requestContext3D( cast (forceSoftware ? "software" : "auto"), PROFILE );
  127. }
  128. function onCreate(_) {
  129. var old = ctx;
  130. for( p in programs )
  131. p.p.dispose();
  132. programs = new Map();
  133. if( old != null ) {
  134. //if( old.driverInfo != "Disposed" ) throw "Duplicate onCreate()";
  135. old.dispose();
  136. ctx = s3d.context3D;
  137. onCreateCallback(true);
  138. } else {
  139. ctx = s3d.context3D;
  140. if( tdisposed == null ) {
  141. tdisposed = ctx.createTexture(1, 1, flash.display3D.Context3DTextureFormat.BGRA, false);
  142. tdisposed.dispose();
  143. }
  144. onCreateCallback(false);
  145. }
  146. }
  147. override function hasFeature( f : Feature ) : Bool {
  148. return switch( f ) {
  149. case HardwareAccelerated: ctx != null && ctx.driverInfo.toLowerCase().indexOf("software") == -1;
  150. case StandardDerivatives, FloatTextures: isStandardMode;
  151. case MultipleRenderTargets: (PROFILE == cast "standard") || (PROFILE == cast "standardExtended");
  152. default: false;
  153. }
  154. }
  155. override function resize(width, height) {
  156. try {
  157. ctx.configureBackBuffer(width, height, antiAlias);
  158. this.width = width;
  159. this.height = height;
  160. @:privateAccess {
  161. defaultDepth.width = width;
  162. defaultDepth.height = height;
  163. }
  164. } catch( e : flash.errors.Error ) {
  165. // large screen but bad video card ?
  166. if( width > 2048 || height > 2048 ) {
  167. if( width > 2048 ) width = 2048;
  168. if( height > 2048 ) height = 2048;
  169. resize(width, height);
  170. } else
  171. throw new flash.errors.Error("" + e+" (" + width + "x" + height + ")");
  172. }
  173. }
  174. override function clear( ?color : h3d.Vector, ?depth : Float, ?stencil : Int ) {
  175. var mask = 0;
  176. if( color != null ) mask |= flash.display3D.Context3DClearMask.COLOR;
  177. if( depth != null ) mask |= flash.display3D.Context3DClearMask.DEPTH;
  178. if( stencil != null ) mask |= flash.display3D.Context3DClearMask.STENCIL;
  179. ctx.clear( color == null ? 0 : color.r, color == null ? 0 : color.g, color == null ? 0 : color.b, color == null ? 1 : color.a, depth == null ? 1 : depth, stencil == null ? 0 : stencil, mask);
  180. }
  181. override function captureRenderBuffer( pixels : hxd.Pixels ) {
  182. if( renderTargets != 0 )
  183. throw "Can't capture render target in flash";
  184. var bmp = new flash.display.BitmapData(pixels.width, pixels.height, true, 0);
  185. ctx.drawToBitmapData(bmp);
  186. var pix = bmp.getPixels(bmp.rect);
  187. bmp.dispose();
  188. var b = pixels.bytes.getData();
  189. b.position = 0;
  190. b.writeBytes(pix, 0, pixels.width * pixels.height * 4);
  191. @:privateAccess pixels.innerFormat = ARGB;
  192. pixels.flags.set(AlphaPremultiplied);
  193. }
  194. override function dispose() {
  195. s3d.removeEventListener(flash.events.Event.CONTEXT3D_CREATE, onCreate);
  196. if( ctx != null ) ctx.dispose();
  197. ctx = null;
  198. }
  199. override function isDisposed() {
  200. return ctx == null || ctx.driverInfo == "Disposed";
  201. }
  202. override function present() {
  203. ctx.present();
  204. }
  205. override function disposeTexture( t : h3d.mat.Texture ) {
  206. if( t.t != null ) {
  207. t.t.dispose();
  208. t.t = null;
  209. }
  210. }
  211. override function allocVertexes( buf : ManagedBuffer ) : VertexBuffer {
  212. var v;
  213. try {
  214. v = ctx.createVertexBuffer(buf.size, buf.stride);
  215. } catch( e : flash.errors.Error ) {
  216. // too many resources / out of memory
  217. if( e.errorID == 3691 )
  218. return null;
  219. throw e;
  220. }
  221. return new VertexWrapper(v, buf);
  222. }
  223. override function allocIndexes( count : Int, is32 : Bool ) : IndexBuffer {
  224. if( is32 )
  225. throw "32 bit indexes are not supported";
  226. try {
  227. return ctx.createIndexBuffer(count);
  228. } catch( e : flash.errors.Error ) {
  229. // too many resources / out of memory
  230. if( e.errorID == 3691 )
  231. return null;
  232. throw e;
  233. }
  234. }
  235. function getMipLevels( t : h3d.mat.Texture ) {
  236. if( !t.flags.has(MipMapped) )
  237. return 0;
  238. var levels = 0;
  239. while( t.width > (1 << levels) || t.height > (1 << levels) )
  240. levels++;
  241. return levels;
  242. }
  243. override function isSupportedFormat( fmt : h3d.mat.Data.TextureFormat ) {
  244. return switch( fmt ) {
  245. case BGRA: true;
  246. case RGBA16F: true;
  247. default: false;
  248. }
  249. }
  250. override function allocTexture( t : h3d.mat.Texture ) : Texture {
  251. var fmt = switch( t.format ) {
  252. case BGRA: flash.display3D.Context3DTextureFormat.BGRA;
  253. case RGBA16F: flash.display3D.Context3DTextureFormat.RGBA_HALF_FLOAT;
  254. default: throw "Unsupported texture format " + t.format;
  255. }
  256. t.lastFrame = frame;
  257. t.flags.unset(WasCleared);
  258. try {
  259. if( t.flags.has(IsNPOT) ) {
  260. if( t.flags.has(Cube) || t.flags.has(MipMapped) )
  261. throw "Not power of two texture is not supported with these flags";
  262. #if !flash11_8
  263. throw "Support for rectangle texture requires Flash 11.8+ compilation";
  264. #else
  265. return ctx.createRectangleTexture(t.width, t.height, fmt, t.flags.has(Target));
  266. #end
  267. }
  268. if( t.flags.has(Cube) )
  269. return ctx.createCubeTexture(t.width, fmt, t.flags.has(Target), getMipLevels(t));
  270. return ctx.createTexture(t.width, t.height, fmt, t.flags.has(Target), getMipLevels(t));
  271. } catch( e : flash.errors.Error ) {
  272. if( e.errorID == 3691 )
  273. return null;
  274. if( e.errorID == 3694 )
  275. return tdisposed; // our context was disposed, let's return a disposed texture
  276. throw e;
  277. }
  278. }
  279. override function uploadTextureBitmap( t : h3d.mat.Texture, bmp : hxd.BitmapData, mipLevel : Int, side : Int ) {
  280. if( t.t == tdisposed ) return;
  281. if( t.flags.has(Cube) ) {
  282. var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
  283. t.uploadFromBitmapData(bmp.toNative(), side, mipLevel);
  284. } else if( t.flags.has(IsNPOT) ) {
  285. #if flash11_8
  286. var t = flash.Lib.as(t.t, flash.display3D.textures.RectangleTexture);
  287. t.uploadFromBitmapData(bmp.toNative());
  288. #end
  289. } else {
  290. var t = flash.Lib.as(t.t, flash.display3D.textures.Texture);
  291. t.uploadFromBitmapData(bmp.toNative(), mipLevel);
  292. }
  293. }
  294. override function uploadTexturePixels( t : h3d.mat.Texture, pixels : hxd.Pixels, mipLevel : Int, side : Int ) {
  295. if( t.t == tdisposed ) return;
  296. pixels.convert(BGRA);
  297. var data = pixels.bytes.getData();
  298. if( t.flags.has(Cube) ) {
  299. var t = flash.Lib.as(t.t, flash.display3D.textures.CubeTexture);
  300. t.uploadFromByteArray(data, pixels.offset, side, mipLevel);
  301. } else if( t.flags.has(IsNPOT) ) {
  302. #if flash11_8
  303. var t = flash.Lib.as(t.t, flash.display3D.textures.RectangleTexture);
  304. t.uploadFromByteArray(data, pixels.offset);
  305. #end
  306. } else {
  307. var t = flash.Lib.as(t.t, flash.display3D.textures.Texture);
  308. t.uploadFromByteArray(data, pixels.offset, mipLevel);
  309. }
  310. }
  311. override function disposeVertexes( v : VertexBuffer ) {
  312. v.vbuf.dispose();
  313. v.b = null;
  314. }
  315. override function disposeIndexes( i : IndexBuffer ) {
  316. i.dispose();
  317. }
  318. override function setDebug( d : Bool ) {
  319. if( ctx != null ) ctx.enableErrorChecking = d && hasFeature(HardwareAccelerated);
  320. }
  321. override function uploadVertexBuffer( v : VertexBuffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
  322. var data = buf.getNative();
  323. v.vbuf.uploadFromVector( bufPos == 0 ? data : data.slice(bufPos, vertexCount * v.b.stride + bufPos), startVertex, vertexCount );
  324. }
  325. override function uploadVertexBytes( v : VertexBuffer, startVertex : Int, vertexCount : Int, bytes : haxe.io.Bytes, bufPos : Int ) {
  326. v.vbuf.uploadFromByteArray( bytes.getData(), bufPos, startVertex, vertexCount );
  327. }
  328. override function uploadIndexBuffer( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : hxd.IndexBuffer, bufPos : Int ) {
  329. var data = buf.getNative();
  330. i.uploadFromVector( bufPos == 0 ? data : data.slice(bufPos, indiceCount + bufPos), startIndice, indiceCount );
  331. }
  332. override function uploadIndexBytes( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
  333. i.uploadFromByteArray(buf.getData(), bufPos, startIndice, indiceCount );
  334. }
  335. override function selectMaterial( pass : Pass ) {
  336. selectMaterialBits(@:privateAccess pass.bits);
  337. if( pass.colorMask != curColorMask ) {
  338. var m = pass.colorMask;
  339. ctx.setColorMask(m & 1 != 0, m & 2 != 0, m & 4 != 0, m & 8 != 0);
  340. curColorMask = m;
  341. }
  342. var s = pass.stencil != null ? pass.stencil : defStencil;
  343. @:privateAccess selectStencilBits(s.opBits, s.maskBits);
  344. }
  345. function selectMaterialBits( bits : Int ) {
  346. var diff = bits ^ curMatBits;
  347. if( curMatBits < 0 ) diff = -1;
  348. if( diff == 0 )
  349. return;
  350. if( diff & Pass.culling_mask != 0 )
  351. ctx.setCulling(FACE[Pass.getCulling(bits)]);
  352. if( diff & (Pass.blendSrc_mask | Pass.blendDst_mask | Pass.blendAlphaSrc_mask | Pass.blendAlphaDst_mask) != 0 ) {
  353. var csrc = Pass.getBlendSrc(bits);
  354. var cdst = Pass.getBlendDst(bits);
  355. var asrc = Pass.getBlendAlphaSrc(bits);
  356. var adst = Pass.getBlendAlphaDst(bits);
  357. if( csrc == asrc && cdst == adst ) {
  358. if( (csrc | cdst) > BLEND.length ) throw "Blend operation not supported on flash";
  359. ctx.setBlendFactors(BLEND[csrc], BLEND[cdst]);
  360. } else {
  361. throw "Alpha blend functions not supported on flash";
  362. }
  363. }
  364. if( diff & (Pass.blendOp_mask | Pass.blendAlphaOp_mask) != 0 ) {
  365. var cop = Pass.getBlendOp(bits);
  366. var aop = Pass.getBlendAlphaOp(bits);
  367. if( cop != 0 || aop != 0 )
  368. throw "Custom blend operation not supported on flash";
  369. }
  370. if( diff & (Pass.depthWrite_mask | Pass.depthTest_mask) != 0 ) {
  371. var write = Pass.getDepthWrite(bits) != 0;
  372. var cmp = Pass.getDepthTest(bits);
  373. ctx.setDepthTest(write, COMPARE[cmp]);
  374. }
  375. curMatBits = bits;
  376. }
  377. function selectStencilBits( opBits : Int, maskBits : Int ) {
  378. var diffOp = opBits ^ curStOpBits;
  379. var diffMask = maskBits ^ curStMaskBits;
  380. if( (diffOp | diffMask) == 0 ) return;
  381. if( diffOp & (Stencil.frontTest_mask | Stencil.frontSTfail_mask | Stencil.frontDPfail_mask | Stencil.frontPass_mask) != 0 ) {
  382. ctx.setStencilActions(
  383. FACE[Type.enumIndex(Front)],
  384. COMPARE[Stencil.getFrontTest(opBits)],
  385. STENCIL_OP[Stencil.getFrontPass(opBits)],
  386. STENCIL_OP[Stencil.getFrontDPfail(opBits)],
  387. STENCIL_OP[Stencil.getFrontSTfail(opBits)]);
  388. }
  389. if( diffOp & (Stencil.backTest_mask | Stencil.backSTfail_mask | Stencil.backDPfail_mask | Stencil.backPass_mask) != 0 ) {
  390. ctx.setStencilActions(
  391. FACE[Type.enumIndex(Back)],
  392. COMPARE[Stencil.getBackTest(opBits)],
  393. STENCIL_OP[Stencil.getBackPass(opBits)],
  394. STENCIL_OP[Stencil.getBackDPfail(opBits)],
  395. STENCIL_OP[Stencil.getBackSTfail(opBits)]);
  396. }
  397. if( diffMask != 0 ) {
  398. ctx.setStencilReferenceValue(
  399. Stencil.getReference(maskBits),
  400. Stencil.getReadMask(maskBits),
  401. Stencil.getWriteMask(maskBits));
  402. }
  403. curStOpBits = opBits;
  404. curStMaskBits = maskBits;
  405. }
  406. function compileShader( s : hxsl.RuntimeShader.RuntimeShaderData, usedTextures : Array<Bool> ) {
  407. //trace(hxsl.Printer.shaderToString(s.data));
  408. var agalVersion = isStandardMode ? 2 : 1;
  409. var agal = hxsl.AgalOut.toAgal(s, agalVersion);
  410. //var old = format.agal.Tools.toString(agal);
  411. var optim = new hxsl.AgalOptim();
  412. agal = optim.optimize(agal);
  413. #if debug
  414. var maxVarying = format.agal.Tools.getProps(RVar, !s.vertex, agalVersion).count;
  415. var maxTextures = format.agal.Tools.getProps(RTexture, !s.vertex, agalVersion).count;
  416. for( op in agal.code )
  417. optim.iter(op, function(r, _) {
  418. switch( r.t ) {
  419. case RVar:
  420. if( r.index >= maxVarying ) {
  421. var vars = [];
  422. for( v in s.data.vars )
  423. switch( v.kind ) {
  424. case Var: vars.push(v.name);
  425. default:
  426. }
  427. throw "Too many varying for this shader ("+vars.join(",")+")";
  428. }
  429. case RTexture:
  430. if( r.index >= maxTextures ) {
  431. var vars = [];
  432. for( v in s.data.vars )
  433. switch( v.type ) {
  434. case TSampler2D, TSamplerCube: vars.push(v.name);
  435. default:
  436. }
  437. throw "Too many textures for this shader ("+vars.join(",")+")";
  438. }
  439. default:
  440. }
  441. });
  442. #end
  443. //var opt = format.agal.Tools.toString(agal);
  444. for( op in agal.code )
  445. switch( op ) {
  446. case OTex(_, _, t): usedTextures[t.index] = true;
  447. default:
  448. }
  449. var size = s.globalsSize+s.paramsSize;
  450. var max = format.agal.Tools.getProps(RConst, !s.vertex, agalVersion).count;
  451. if( size > max )
  452. throw (s.vertex?"Vertex ":"Fragment ") + " shader uses " + size+" constant registers while " + max + " is allowed";
  453. var o = new haxe.io.BytesOutput();
  454. new format.agal.Writer(o).write(agal);
  455. return { agal : agal, bytes : o.getBytes() };
  456. }
  457. override function getNativeShaderCode( shader : hxsl.RuntimeShader ) {
  458. var vertex = compileShader(shader.vertex, []).agal;
  459. var fragment = compileShader(shader.fragment, []).agal;
  460. function fmt( agal, data : hxsl.RuntimeShader.RuntimeShaderData ) {
  461. var str = format.agal.Tools.toString(agal);
  462. return ~/c([0-9]+)(.[xyz]+)?/g.map(str, function(r) {
  463. var cid = Std.parseInt(r.matched(1)) << 2;
  464. var swiz = r.matched(2);
  465. if( swiz != null ) {
  466. var d = swiz.charCodeAt(1) - 'x'.code;
  467. cid += d;
  468. swiz = "." + [for( i in 1...swiz.length ) String.fromCharCode(swiz.charCodeAt(i) - d)].join("");
  469. }
  470. var name = "C" + cid;
  471. var g = data.globals;
  472. while( g != null ) {
  473. if( g.path == "__consts__" && cid >= g.pos && cid < g.pos + (switch(g.type) { case TArray(TFloat, SConst(n)): n; default: 0; } ) && swiz == ".x" ) {
  474. swiz = null;
  475. name = "" + data.consts[cid - g.pos];
  476. break;
  477. }
  478. if( g.pos == cid ) {
  479. name = g.path;
  480. break;
  481. }
  482. g = g.next;
  483. }
  484. var p = data.params;
  485. while( p != null ) {
  486. if( p.pos + (data.globalsSize << 2) == cid ) {
  487. name = p.name;
  488. break;
  489. }
  490. p = p.next;
  491. }
  492. return swiz == null ? name : name+swiz;
  493. });
  494. }
  495. return fmt(vertex, shader.vertex) + "\n" + fmt(fragment, shader.fragment);
  496. }
  497. function initShader( shader : hxsl.RuntimeShader ) {
  498. var p = new CompiledShader(shader);
  499. p.p = ctx.createProgram();
  500. var cachedShader = null;
  501. var file = SHADER_CACHE_PATH;
  502. if( SHADER_CACHE_PATH != null ) {
  503. file += shader.signature;
  504. if( !isStandardMode ) file += "1";
  505. file += ".shader";
  506. try cachedShader = haxe.Unserializer.run(hxd.File.getBytes(file).toString()) catch( e : Dynamic ) { };
  507. }
  508. if( cachedShader == null ) {
  509. cachedShader = {
  510. vertex : compileShader(shader.vertex,[]).bytes,
  511. fragment : compileShader(shader.fragment, p.usedTextures).bytes,
  512. tex : p.usedTextures,
  513. };
  514. if( file != null )
  515. hxd.File.saveBytes(file, haxe.io.Bytes.ofString(haxe.Serializer.run(cachedShader)));
  516. } else {
  517. p.usedTextures = cachedShader.tex;
  518. }
  519. var vdata = cachedShader.vertex.getData();
  520. var fdata = cachedShader.fragment.getData();
  521. vdata.endian = flash.utils.Endian.LITTLE_ENDIAN;
  522. fdata.endian = flash.utils.Endian.LITTLE_ENDIAN;
  523. var pos = 0;
  524. var inputNames = [];
  525. for( v in shader.vertex.data.vars )
  526. if( v.kind == Input ) {
  527. var size;
  528. var fmt = switch( v.type ) {
  529. case TBytes(4): size = 1; flash.display3D.Context3DVertexBufferFormat.BYTES_4;
  530. case TFloat: size = 1; flash.display3D.Context3DVertexBufferFormat.FLOAT_1;
  531. case TVec(2, VFloat): size = 2; flash.display3D.Context3DVertexBufferFormat.FLOAT_2;
  532. case TVec(3, VFloat): size = 3; flash.display3D.Context3DVertexBufferFormat.FLOAT_3;
  533. case TVec(4, VFloat): size = 4; flash.display3D.Context3DVertexBufferFormat.FLOAT_4;
  534. default: throw "unsupported input " + v.type;
  535. }
  536. var idx = FORMAT.indexOf(fmt);
  537. if( idx < 0 ) throw "assert " + fmt;
  538. p.bufferFormat |= idx << (pos * 3);
  539. inputNames.push(v.name);
  540. p.stride += size;
  541. pos++;
  542. }
  543. p.inputs = InputNames.get(inputNames);
  544. p.p.upload(vdata, fdata);
  545. return p;
  546. }
  547. override function selectShader( shader : hxsl.RuntimeShader ) {
  548. var shaderChanged = false;
  549. var p = programs.get(shader.id);
  550. if( p == null ) {
  551. p = initShader(shader);
  552. programs.set(shader.id, p);
  553. curShader = null;
  554. }
  555. if( p != curShader ) {
  556. ctx.setProgram(p.p);
  557. shaderChanged = true;
  558. curShader = p;
  559. // unbind extra textures
  560. var tcount : Int = shader.fragment.texturesCount + shader.vertex.texturesCount;
  561. while( curTextures.length > tcount ) {
  562. curTextures.pop();
  563. ctx.setTextureAt(curTextures.length, null);
  564. }
  565. // force remapping for sampler bits
  566. for( i in 0...curSamplerBits.length )
  567. curSamplerBits[i] = -1;
  568. // force remapping of vertex buffer
  569. curBuffer = null;
  570. curMultiBuffer[0] = -1;
  571. }
  572. return shaderChanged;
  573. }
  574. override function uploadShaderBuffers( buffers : h3d.shader.Buffers, which : h3d.shader.Buffers.BufferKind ) {
  575. switch( which ) {
  576. case Textures:
  577. for( i in 0...curShader.s.fragment.texturesCount ) {
  578. var t = buffers.fragment.tex[i];
  579. if( t == null || t.isDisposed() ) {
  580. var color = h3d.mat.Defaults.loadingTextureColor;
  581. t = h3d.mat.Texture.fromColor(color,(color>>>24)/255);
  582. }
  583. if( t != null && t.t == null && t.realloc != null ) {
  584. t.alloc();
  585. t.realloc();
  586. }
  587. t.lastFrame = frame;
  588. if( !curShader.usedTextures[i] ) {
  589. if( curTextures[i] != null ) {
  590. ctx.setTextureAt(i, null);
  591. curTextures[i] = null;
  592. curSamplerBits[i] = -1;
  593. }
  594. continue;
  595. }
  596. var cur = curTextures[i];
  597. if( t != cur ) {
  598. ctx.setTextureAt(i, t.t);
  599. curTextures[i] = t;
  600. }
  601. // if we have set one of the texture flag manually or if the shader does not configure the texture flags
  602. if( true /*!t.hasDefaultFlags() || !s.texHasConfig[s.textureMap[i]]*/ ) {
  603. if( cur == null || t.bits != curSamplerBits[i] ) {
  604. ctx.setSamplerStateAt(i, WRAP[t.wrap.getIndex()], FILTER[t.filter.getIndex()], MIP[t.mipMap.getIndex()]);
  605. curSamplerBits[i] = t.bits;
  606. }
  607. } else {
  608. // the texture flags has been set by the shader, so we are in an unkown state
  609. curSamplerBits[i] = -1;
  610. }
  611. }
  612. case Buffers:
  613. if( curShader.s.fragment.bufferCount + curShader.s.vertex.bufferCount > 0 )
  614. throw "Uniform Buffers are not supported";
  615. case Params:
  616. if( curShader.s.vertex.paramsSize > 0 ) ctx.setProgramConstantsFromVector(flash.display3D.Context3DProgramType.VERTEX, curShader.s.vertex.globalsSize, buffers.vertex.params.toData(), curShader.s.vertex.paramsSize);
  617. if( curShader.s.fragment.paramsSize > 0 ) ctx.setProgramConstantsFromVector(flash.display3D.Context3DProgramType.FRAGMENT, curShader.s.fragment.globalsSize, buffers.fragment.params.toData(), curShader.s.fragment.paramsSize);
  618. case Globals:
  619. if( curShader.s.vertex.globalsSize > 0 ) ctx.setProgramConstantsFromVector(flash.display3D.Context3DProgramType.VERTEX, 0, buffers.vertex.globals.toData(), curShader.s.vertex.globalsSize);
  620. if( curShader.s.fragment.globalsSize > 0 ) ctx.setProgramConstantsFromVector(flash.display3D.Context3DProgramType.FRAGMENT, 0, buffers.fragment.globals.toData(), curShader.s.fragment.globalsSize);
  621. }
  622. }
  623. @:access(h3d.impl.ManagedBuffer)
  624. override function selectBuffer( v : Buffer ) {
  625. if( v == curBuffer )
  626. return;
  627. if( curBuffer != null && v.buffer == curManagedBuffer && v.flags.has(RawFormat) == curBuffer.flags.has(RawFormat) ) {
  628. curBuffer = v;
  629. return;
  630. }
  631. if( curShader == null )
  632. throw "No shader selected";
  633. curBuffer = v;
  634. curManagedBuffer = v.buffer; // store if curBuffer is disposed()
  635. curMultiBuffer[0] = -1;
  636. var m = v.buffer.vbuf;
  637. if( m.b.stride < curShader.stride )
  638. throw "Buffer stride (" + m.b.stride + ") and shader stride (" + curShader.stride + ") mismatch";
  639. if( !m.written )
  640. m.finalize(this);
  641. var pos = 0, offset = 0;
  642. var bits = curShader.bufferFormat;
  643. if( v.flags.has(RawFormat) ) {
  644. while( offset < curShader.stride ) {
  645. var size = bits & 7;
  646. ctx.setVertexBufferAt(pos++, m.vbuf, offset, FORMAT[size]);
  647. offset += size == 0 ? 1 : size;
  648. bits >>= 3;
  649. }
  650. } else {
  651. offset = 8; // custom data starts after [position, normal, uv]
  652. for( s in curShader.inputs.names ) {
  653. switch( s ) {
  654. case "position":
  655. ctx.setVertexBufferAt(pos++, m.vbuf, 0, FORMAT[3]);
  656. case "normal":
  657. if( m.b.stride < 6 ) throw "Buffer is missing NORMAL data, set it to RAW format ?" #if track_alloc + @:privateAccess v.allocPos #end;
  658. ctx.setVertexBufferAt(pos++, m.vbuf, 3, FORMAT[3]);
  659. case "uv":
  660. if( m.b.stride < 8 ) throw "Buffer is missing UV data, set it to RAW format ?" #if track_alloc + @:privateAccess v.allocPos #end;
  661. ctx.setVertexBufferAt(pos++, m.vbuf, 6, FORMAT[2]);
  662. default:
  663. var size = bits & 7;
  664. ctx.setVertexBufferAt(pos++, m.vbuf, offset, FORMAT[size]);
  665. offset += size == 0 ? 1 : size;
  666. if( offset > m.b.stride ) throw "Buffer is missing '"+s+"' data, set it to RAW format ?" #if track_alloc + @:privateAccess v.allocPos #end;
  667. }
  668. bits >>= 3;
  669. }
  670. }
  671. for( i in pos...curAttributes )
  672. ctx.setVertexBufferAt(i, null);
  673. curAttributes = pos;
  674. }
  675. override function getShaderInputNames() {
  676. return curShader.inputs;
  677. }
  678. override function selectMultiBuffers( buffers : Buffer.BufferOffset ) {
  679. // select the multiple buffers elements
  680. var changed = false;
  681. var b = buffers;
  682. var i = 0;
  683. while( b != null || i < curAttributes ) {
  684. if( b == null || b.id != curMultiBuffer[i] ) {
  685. changed = true;
  686. break;
  687. }
  688. b = b.next;
  689. i++;
  690. }
  691. if( changed ) {
  692. var pos = 0, offset = 0;
  693. var bits = curShader.bufferFormat;
  694. var b = buffers;
  695. while( offset < curShader.stride ) {
  696. var size = bits & 7;
  697. if( b.buffer.next != null )
  698. throw "Buffer is split";
  699. var vbuf = @:privateAccess b.buffer.buffer.vbuf;
  700. if( !vbuf.written ) vbuf.finalize(this);
  701. ctx.setVertexBufferAt(pos, vbuf.vbuf, b.offset, FORMAT[size]);
  702. curMultiBuffer[pos] = b.id;
  703. offset += size == 0 ? 1 : size;
  704. bits >>= 3;
  705. pos++;
  706. b = b.next;
  707. }
  708. for( i in pos...curAttributes )
  709. ctx.setVertexBufferAt(i, null);
  710. curAttributes = pos;
  711. curBuffer = null;
  712. }
  713. }
  714. function debugDraw( ibuf : IndexBuffer, startIndex : Int, ntriangles : Int ) {
  715. try {
  716. ctx.drawTriangles(ibuf, startIndex, ntriangles);
  717. } catch( e : flash.errors.Error ) {
  718. // this error should not happen, but sometime does in debug mode (?)
  719. if( e.errorID != 3605 )
  720. throw e;
  721. }
  722. }
  723. override function allocDepthBuffer(b:h3d.mat.Texture):DepthBuffer {
  724. throw "You can't allocate custom depth buffer on this platform.";
  725. }
  726. override function getDefaultDepthBuffer() {
  727. return defaultDepth;
  728. }
  729. override function draw( ibuf : IndexBuffer, startIndex : Int, ntriangles : Int ) {
  730. if( enableDraw ) {
  731. if( ctx.enableErrorChecking )
  732. debugDraw(ibuf, startIndex, ntriangles);
  733. else
  734. ctx.drawTriangles(ibuf, startIndex, ntriangles);
  735. }
  736. }
  737. override function setRenderZone( x : Int, y : Int, width : Int, height : Int ) {
  738. if( x == 0 && y == 0 && width < 0 && height < 0 ) {
  739. enableDraw = true;
  740. ctx.setScissorRectangle(null);
  741. } else {
  742. if( x < 0 ) {
  743. width += x;
  744. x = 0;
  745. }
  746. if( y < 0 ) {
  747. height += y;
  748. y = 0;
  749. }
  750. var tw = renderTargets == 0 ? this.width : 9999;
  751. var th = renderTargets == 0 ? this.height : 9999;
  752. if( x + width > tw ) width = tw - x;
  753. if( y + height > th ) height = th - y;
  754. enableDraw = width > 0 && height > 0;
  755. if( enableDraw )
  756. ctx.setScissorRectangle(new flash.geom.Rectangle(x, y, width, height));
  757. }
  758. }
  759. override function setRenderTarget( t : Null<h3d.mat.Texture>, face = 0, mipLevel = 0 ) {
  760. if( mipLevel != 0 )
  761. throw "Cannot render to mipmap in flash, use upload()";
  762. if( renderTargets > 1 ) {
  763. for( i in 1...renderTargets )
  764. ctx.setRenderToTexture(null, false, 0, 0, i);
  765. renderTargets = 1;
  766. }
  767. if( t == null ) {
  768. ctx.setRenderToBackBuffer();
  769. renderTargets = 0;
  770. } else {
  771. if( t.t == null )
  772. t.alloc();
  773. ctx.setRenderToTexture(t.t, t.depthBuffer != null, 0, face);
  774. renderTargets = 1;
  775. t.lastFrame = frame;
  776. // make sure we at least clear the color the first time
  777. if( flashVersion >= 15 && !t.flags.has(WasCleared) ) {
  778. t.flags.set(WasCleared);
  779. ctx.clear(0, 0, 0, 0, 1, 0, flash.display3D.Context3DClearMask.COLOR);
  780. }
  781. }
  782. reset();
  783. }
  784. override function setRenderTargets( textures : Array<h3d.mat.Texture>) {
  785. if( textures.length == 0 ) {
  786. setRenderTarget(null);
  787. return;
  788. }
  789. var hasDepth = textures[0].depthBuffer != null;
  790. for( i in 0...textures.length ) {
  791. var t = textures[i];
  792. if( t.t == null )
  793. t.alloc();
  794. ctx.setRenderToTexture(t.t, hasDepth, 0, 0, i);
  795. t.lastFrame = frame;
  796. }
  797. for( i in textures.length...renderTargets )
  798. ctx.setRenderToTexture(null, false, 0, 0, i);
  799. renderTargets = textures.length;
  800. reset();
  801. }
  802. static var BLEND = [
  803. flash.display3D.Context3DBlendFactor.ONE,
  804. flash.display3D.Context3DBlendFactor.ZERO,
  805. flash.display3D.Context3DBlendFactor.SOURCE_ALPHA,
  806. flash.display3D.Context3DBlendFactor.SOURCE_COLOR,
  807. flash.display3D.Context3DBlendFactor.DESTINATION_ALPHA,
  808. flash.display3D.Context3DBlendFactor.DESTINATION_COLOR,
  809. flash.display3D.Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA,
  810. flash.display3D.Context3DBlendFactor.ONE_MINUS_SOURCE_COLOR,
  811. flash.display3D.Context3DBlendFactor.ONE_MINUS_DESTINATION_ALPHA,
  812. flash.display3D.Context3DBlendFactor.ONE_MINUS_DESTINATION_COLOR
  813. ];
  814. static var FACE = [
  815. flash.display3D.Context3DTriangleFace.NONE,
  816. flash.display3D.Context3DTriangleFace.BACK,
  817. flash.display3D.Context3DTriangleFace.FRONT,
  818. flash.display3D.Context3DTriangleFace.FRONT_AND_BACK,
  819. ];
  820. static var COMPARE = [
  821. flash.display3D.Context3DCompareMode.ALWAYS,
  822. flash.display3D.Context3DCompareMode.NEVER,
  823. flash.display3D.Context3DCompareMode.EQUAL,
  824. flash.display3D.Context3DCompareMode.NOT_EQUAL,
  825. flash.display3D.Context3DCompareMode.GREATER,
  826. flash.display3D.Context3DCompareMode.GREATER_EQUAL,
  827. flash.display3D.Context3DCompareMode.LESS,
  828. flash.display3D.Context3DCompareMode.LESS_EQUAL,
  829. ];
  830. static var STENCIL_OP = [
  831. flash.display3D.Context3DStencilAction.KEEP,
  832. flash.display3D.Context3DStencilAction.ZERO,
  833. flash.display3D.Context3DStencilAction.SET,
  834. flash.display3D.Context3DStencilAction.INCREMENT_SATURATE,
  835. flash.display3D.Context3DStencilAction.INCREMENT_WRAP,
  836. flash.display3D.Context3DStencilAction.DECREMENT_SATURATE,
  837. flash.display3D.Context3DStencilAction.DECREMENT_WRAP,
  838. flash.display3D.Context3DStencilAction.INVERT,
  839. ];
  840. static var FORMAT = [
  841. flash.display3D.Context3DVertexBufferFormat.BYTES_4,
  842. flash.display3D.Context3DVertexBufferFormat.FLOAT_1,
  843. flash.display3D.Context3DVertexBufferFormat.FLOAT_2,
  844. flash.display3D.Context3DVertexBufferFormat.FLOAT_3,
  845. flash.display3D.Context3DVertexBufferFormat.FLOAT_4,
  846. ];
  847. static var WRAP = [
  848. flash.display3D.Context3DWrapMode.CLAMP,
  849. flash.display3D.Context3DWrapMode.REPEAT,
  850. ];
  851. static var FILTER = [
  852. flash.display3D.Context3DTextureFilter.NEAREST,
  853. flash.display3D.Context3DTextureFilter.LINEAR,
  854. ];
  855. static var MIP = [
  856. flash.display3D.Context3DMipFilter.MIPNONE,
  857. flash.display3D.Context3DMipFilter.MIPNEAREST,
  858. flash.display3D.Context3DMipFilter.MIPLINEAR,
  859. ];
  860. }
  861. #end