Stage3dDriver.hx 31 KB

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