callback.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*
  2. * Copyright 2011-2016 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  4. */
  5. #include "common.h"
  6. #include "bgfx_utils.h"
  7. #include <bx/allocator.h>
  8. #include <bx/string.h>
  9. #include <bx/crtimpl.h>
  10. #include "aviwriter.h"
  11. #include <inttypes.h>
  12. struct PosColorVertex
  13. {
  14. float m_x;
  15. float m_y;
  16. float m_z;
  17. uint32_t m_abgr;
  18. static void init()
  19. {
  20. ms_decl
  21. .begin()
  22. .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
  23. .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true)
  24. .end();
  25. };
  26. static bgfx::VertexDecl ms_decl;
  27. };
  28. bgfx::VertexDecl PosColorVertex::ms_decl;
  29. static PosColorVertex s_cubeVertices[8] =
  30. {
  31. {-1.0f, 1.0f, 1.0f, 0xff000000 },
  32. { 1.0f, 1.0f, 1.0f, 0xff0000ff },
  33. {-1.0f, -1.0f, 1.0f, 0xff00ff00 },
  34. { 1.0f, -1.0f, 1.0f, 0xff00ffff },
  35. {-1.0f, 1.0f, -1.0f, 0xffff0000 },
  36. { 1.0f, 1.0f, -1.0f, 0xffff00ff },
  37. {-1.0f, -1.0f, -1.0f, 0xffffff00 },
  38. { 1.0f, -1.0f, -1.0f, 0xffffffff },
  39. };
  40. static const uint16_t s_cubeIndices[36] =
  41. {
  42. 0, 1, 2, // 0
  43. 1, 3, 2,
  44. 4, 6, 5, // 2
  45. 5, 6, 7,
  46. 0, 2, 4, // 4
  47. 4, 2, 6,
  48. 1, 5, 3, // 6
  49. 5, 7, 3,
  50. 0, 4, 1, // 8
  51. 4, 5, 1,
  52. 2, 3, 6, // 10
  53. 6, 3, 7,
  54. };
  55. void imageWriteTga(bx::WriterI* _writer, uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _src, bool _grayscale, bool _yflip, bx::Error* _err)
  56. {
  57. BX_ERROR_SCOPE(_err);
  58. uint8_t type = _grayscale ? 3 : 2;
  59. uint8_t bpp = _grayscale ? 8 : 32;
  60. uint8_t header[18] = {};
  61. header[ 2] = type;
  62. header[12] = _width &0xff;
  63. header[13] = (_width >>8)&0xff;
  64. header[14] = _height &0xff;
  65. header[15] = (_height>>8)&0xff;
  66. header[16] = bpp;
  67. header[17] = 32;
  68. bx::write(_writer, header, sizeof(header), _err);
  69. uint32_t dstPitch = _width*bpp/8;
  70. if (_yflip)
  71. {
  72. uint8_t* data = (uint8_t*)_src + _pitch*_height - _pitch;
  73. for (uint32_t yy = 0; yy < _height; ++yy)
  74. {
  75. bx::write(_writer, data, dstPitch, _err);
  76. data -= _pitch;
  77. }
  78. }
  79. else if (_pitch == dstPitch)
  80. {
  81. bx::write(_writer, _src, _height*_pitch, _err);
  82. }
  83. else
  84. {
  85. uint8_t* data = (uint8_t*)_src;
  86. for (uint32_t yy = 0; yy < _height; ++yy)
  87. {
  88. bx::write(_writer, data, dstPitch, _err);
  89. data += _pitch;
  90. }
  91. }
  92. }
  93. void saveTga(const char* _filePath, uint32_t _width, uint32_t _height, uint32_t _srcPitch, const void* _src, bool _grayscale, bool _yflip)
  94. {
  95. bx::CrtFileWriter writer;
  96. bx::Error err;
  97. if (bx::open(&writer, _filePath, false, &err) )
  98. {
  99. imageWriteTga(&writer, _width, _height, _srcPitch, _src, _grayscale, _yflip, &err);
  100. bx::close(&writer);
  101. }
  102. }
  103. struct BgfxCallback : public bgfx::CallbackI
  104. {
  105. virtual ~BgfxCallback()
  106. {
  107. }
  108. virtual void fatal(bgfx::Fatal::Enum _code, const char* _str) BX_OVERRIDE
  109. {
  110. // Something unexpected happened, inform user and bail out.
  111. dbgPrintf("Fatal error: 0x%08x: %s", _code, _str);
  112. // Must terminate, continuing will cause crash anyway.
  113. abort();
  114. }
  115. virtual void traceVargs(const char* _filePath, uint16_t _line, const char* _format, va_list _argList) BX_OVERRIDE
  116. {
  117. dbgPrintf("%s (%d): ", _filePath, _line);
  118. dbgPrintfVargs(_format, _argList);
  119. }
  120. virtual uint32_t cacheReadSize(uint64_t _id) BX_OVERRIDE
  121. {
  122. char filePath[256];
  123. bx::snprintf(filePath, sizeof(filePath), "temp/%016" PRIx64, _id);
  124. // Use cache id as filename.
  125. bx::FileReaderI* reader = entry::getFileReader();
  126. bx::Error err;
  127. if (bx::open(reader, filePath, &err) )
  128. {
  129. uint32_t size = bx::getSize(reader);
  130. bx::close(reader);
  131. // Return size of shader file.
  132. return size;
  133. }
  134. // Return 0 if shader is not found.
  135. return 0;
  136. }
  137. virtual bool cacheRead(uint64_t _id, void* _data, uint32_t _size) BX_OVERRIDE
  138. {
  139. char filePath[256];
  140. bx::snprintf(filePath, sizeof(filePath), "temp/%016" PRIx64, _id);
  141. // Use cache id as filename.
  142. bx::FileReaderI* reader = entry::getFileReader();
  143. bx::Error err;
  144. if (bx::open(reader, filePath, &err) )
  145. {
  146. // Read shader.
  147. uint32_t result = bx::read(reader, _data, _size, &err);
  148. bx::close(reader);
  149. // Make sure that read size matches requested size.
  150. return result == _size;
  151. }
  152. // Shader is not found in cache, needs to be rebuilt.
  153. return false;
  154. }
  155. virtual void cacheWrite(uint64_t _id, const void* _data, uint32_t _size) BX_OVERRIDE
  156. {
  157. char filePath[256];
  158. bx::snprintf(filePath, sizeof(filePath), "temp/%016" PRIx64, _id);
  159. // Use cache id as filename.
  160. bx::FileWriterI* writer = entry::getFileWriter();
  161. bx::Error err;
  162. if (bx::open(writer, filePath, false, &err) )
  163. {
  164. // Write shader to cache location.
  165. bx::write(writer, _data, _size, &err);
  166. bx::close(writer);
  167. }
  168. }
  169. virtual void screenShot(const char* _filePath, uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _data, uint32_t /*_size*/, bool _yflip) BX_OVERRIDE
  170. {
  171. char temp[1024];
  172. // Save screen shot as TGA.
  173. bx::snprintf(temp, BX_COUNTOF(temp), "%s.tga", _filePath);
  174. saveTga(temp, _width, _height, _pitch, _data, false, _yflip);
  175. }
  176. virtual void captureBegin(uint32_t _width, uint32_t _height, uint32_t /*_pitch*/, bgfx::TextureFormat::Enum /*_format*/, bool _yflip) BX_OVERRIDE
  177. {
  178. m_writer = BX_NEW(entry::getAllocator(), AviWriter)(entry::getFileWriter() );
  179. if (!m_writer->open("temp/capture.avi", _width, _height, 60, _yflip) )
  180. {
  181. BX_DELETE(entry::getAllocator(), m_writer);
  182. m_writer = NULL;
  183. }
  184. }
  185. virtual void captureEnd() BX_OVERRIDE
  186. {
  187. if (NULL != m_writer)
  188. {
  189. m_writer->close();
  190. BX_DELETE(entry::getAllocator(), m_writer);
  191. m_writer = NULL;
  192. }
  193. }
  194. virtual void captureFrame(const void* _data, uint32_t /*_size*/) BX_OVERRIDE
  195. {
  196. if (NULL != m_writer)
  197. {
  198. m_writer->frame(_data);
  199. }
  200. }
  201. AviWriter* m_writer;
  202. };
  203. class BgfxAllocator : public bx::AllocatorI
  204. {
  205. public:
  206. BgfxAllocator()
  207. : m_numBlocks(0)
  208. , m_maxBlocks(0)
  209. {
  210. }
  211. virtual ~BgfxAllocator()
  212. {
  213. }
  214. virtual void* realloc(void* _ptr, size_t _size, size_t _align, const char* _file, uint32_t _line) BX_OVERRIDE
  215. {
  216. if (0 == _size)
  217. {
  218. if (NULL != _ptr)
  219. {
  220. if (BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT >= _align)
  221. {
  222. dbgPrintf("%s(%d): FREE %p\n", _file, _line, _ptr);
  223. ::free(_ptr);
  224. --m_numBlocks;
  225. }
  226. else
  227. {
  228. bx::alignedFree(this, _ptr, _align, _file, _line);
  229. }
  230. }
  231. return NULL;
  232. }
  233. else if (NULL == _ptr)
  234. {
  235. if (BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT >= _align)
  236. {
  237. void* ptr = ::malloc(_size);
  238. dbgPrintf("%s(%d): ALLOC %p of %d byte(s)\n", _file, _line, ptr, _size);
  239. ++m_numBlocks;
  240. m_maxBlocks = bx::uint32_max(m_maxBlocks, m_numBlocks);
  241. return ptr;
  242. }
  243. return bx::alignedAlloc(this, _size, _align, _file, _line);
  244. }
  245. if (BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT >= _align)
  246. {
  247. void* ptr = ::realloc(_ptr, _size);
  248. dbgPrintf("%s(%d): REALLOC %p (old %p) of %d byte(s)\n", _file, _line, ptr, _ptr, _size);
  249. if (NULL == _ptr)
  250. {
  251. ++m_numBlocks;
  252. m_maxBlocks = bx::uint32_max(m_maxBlocks, m_numBlocks);
  253. }
  254. return ptr;
  255. }
  256. return bx::alignedRealloc(this, _ptr, _size, _align, _file, _line);
  257. }
  258. void dumpStats() const
  259. {
  260. dbgPrintf("Allocator stats: num blocks %d (peak: %d)\n", m_numBlocks, m_maxBlocks);
  261. }
  262. private:
  263. uint32_t m_numBlocks;
  264. uint32_t m_maxBlocks;
  265. };
  266. int _main_(int _argc, char** _argv)
  267. {
  268. Args args(_argc, _argv);
  269. BgfxCallback callback;
  270. BgfxAllocator allocator;
  271. uint32_t width = 1280;
  272. uint32_t height = 720;
  273. // Enumerate supported backend renderers.
  274. bgfx::RendererType::Enum renderers[bgfx::RendererType::Count];
  275. uint8_t numRenderers = bgfx::getSupportedRenderers(BX_COUNTOF(renderers), renderers);
  276. bgfx::init(bgfx::RendererType::Count == args.m_type
  277. ? renderers[bx::getHPCounter() % numRenderers] /* randomize renderer */
  278. : args.m_type
  279. , args.m_pciId
  280. , 0
  281. , &callback // custom callback handler
  282. , &allocator // custom allocator
  283. );
  284. bgfx::reset(width, height, BGFX_RESET_CAPTURE|BGFX_RESET_MSAA_X16);
  285. // Enable debug text.
  286. bgfx::setDebug(BGFX_DEBUG_TEXT);
  287. // Set view 0 default viewport.
  288. bgfx::setViewRect(0, 0, 0, 1280, 720);
  289. // Set view 0 clear state.
  290. bgfx::setViewClear(0
  291. , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
  292. , 0x303030ff
  293. , 1.0f
  294. , 0
  295. );
  296. // Create vertex stream declaration.
  297. PosColorVertex::init();
  298. // Create static vertex buffer.
  299. bgfx::VertexBufferHandle vbh = bgfx::createVertexBuffer(
  300. bgfx::makeRef(s_cubeVertices, sizeof(s_cubeVertices) )
  301. , PosColorVertex::ms_decl
  302. );
  303. // Create static index buffer.
  304. bgfx::IndexBufferHandle ibh = bgfx::createIndexBuffer(bgfx::makeRef(s_cubeIndices, sizeof(s_cubeIndices) ) );
  305. // Create program from shaders.
  306. bgfx::ProgramHandle program = loadProgram("vs_callback", "fs_callback");
  307. float time = 0.0f;
  308. const bgfx::RendererType::Enum rendererType = bgfx::getRendererType();
  309. // 5 second 60Hz video
  310. for (uint32_t frame = 0; frame < 300; ++frame)
  311. {
  312. // This dummy draw call is here to make sure that view 0 is cleared
  313. // if no other draw calls are submitted to view 0.
  314. bgfx::touch(0);
  315. int64_t now = bx::getHPCounter();
  316. static int64_t last = now;
  317. const int64_t frameTime = now - last;
  318. last = now;
  319. const double freq = double(bx::getHPFrequency() );
  320. const double toMs = 1000.0/freq;
  321. // Use debug font to print information about this example.
  322. bgfx::dbgTextClear();
  323. bgfx::dbgTextPrintf( 0, 1, 0x4f, "bgfx/examples/07-callback");
  324. bgfx::dbgTextPrintf( 0, 2, 0x6f, "Description: Implementing application specific callbacks for taking screen shots,");
  325. bgfx::dbgTextPrintf(13, 3, 0x6f, "caching OpenGL binary shaders, and video capture.");
  326. bgfx::dbgTextPrintf( 0, 4, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs);
  327. bgfx::dbgTextPrintf( 2, 6, 0x0e, "Supported renderers:");
  328. for (uint8_t ii = 0; ii < numRenderers; ++ii)
  329. {
  330. bgfx::dbgTextPrintf( 2, 7+ii, 0x0c, "[%c] %s"
  331. , renderers[ii] == rendererType ? '\xfe' : ' '
  332. , bgfx::getRendererName(renderers[ii])
  333. );
  334. }
  335. float at[3] = { 0.0f, 0.0f, 0.0f };
  336. float eye[3] = { 0.0f, 0.0f, -35.0f };
  337. float view[16];
  338. float proj[16];
  339. bx::mtxLookAt(view, eye, at);
  340. bx::mtxProj(proj, 60.0f, float(width)/float(height), 0.1f, 100.0f);
  341. // Set view and projection matrix for view 0.
  342. bgfx::setViewTransform(0, view, proj);
  343. time += 1.0f/60.0f;
  344. // Submit 11x11 cubes.
  345. for (uint32_t yy = 0; yy < 11; ++yy)
  346. {
  347. for (uint32_t xx = 0; xx < 11-yy; ++xx)
  348. {
  349. float mtx[16];
  350. bx::mtxRotateXY(mtx, time + xx*0.21f, time + yy*0.37f);
  351. mtx[12] = -15.0f + float(xx)*3.0f;
  352. mtx[13] = -15.0f + float(yy)*3.0f;
  353. mtx[14] = 0.0f;
  354. // Set model matrix for rendering.
  355. bgfx::setTransform(mtx);
  356. // Set vertex and index buffer.
  357. bgfx::setVertexBuffer(vbh);
  358. bgfx::setIndexBuffer(ibh);
  359. // Set render states.
  360. bgfx::setState(BGFX_STATE_DEFAULT);
  361. // Submit primitive for rendering to view 0.
  362. bgfx::submit(0, program);
  363. }
  364. }
  365. // Take screen shot at frame 150.
  366. if (150 == frame)
  367. {
  368. bgfx::saveScreenShot("temp/frame150");
  369. }
  370. // Advance to next frame. Rendering thread will be kicked to
  371. // process submitted rendering primitives.
  372. bgfx::frame();
  373. }
  374. // Cleanup.
  375. bgfx::destroyIndexBuffer(ibh);
  376. bgfx::destroyVertexBuffer(vbh);
  377. bgfx::destroyProgram(program);
  378. // Shutdown bgfx.
  379. bgfx::shutdown();
  380. allocator.dumpStats();
  381. return 0;
  382. }