From 83f151f71b3fe1cb5ef47e96f486e9e9b14f6164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Fri, 19 Dec 2014 21:09:58 -0800 Subject: [PATCH] Added 24-nbody compute shader example. --- README.md | 7 + examples/24-nbody/cs_init_instances.sc | 105 +++++++ examples/24-nbody/cs_update_instances.sc | 67 +++++ examples/24-nbody/fs_particle.sc | 16 ++ examples/24-nbody/makefile | 17 ++ examples/24-nbody/nbody.cpp | 272 ++++++++++++++++++ examples/24-nbody/screenshot.png | Bin 0 -> 57618 bytes examples/24-nbody/uniforms.sh | 20 ++ examples/24-nbody/varying.def.sc | 4 + examples/24-nbody/vs_particle.sc | 23 ++ examples/makefile | 1 + .../shaders/dx11/cs_init_instances.bin | Bin 0 -> 6767 bytes .../shaders/dx11/cs_update_instances.bin | Bin 0 -> 1731 bytes examples/runtime/shaders/dx11/fs_particle.bin | Bin 0 -> 603 bytes examples/runtime/shaders/dx11/vs_particle.bin | Bin 0 -> 1149 bytes examples/runtime/shaders/dx9/fs_particle.bin | Bin 0 -> 404 bytes examples/runtime/shaders/dx9/vs_particle.bin | Bin 0 -> 682 bytes .../shaders/gles/cs_init_instances.bin | Bin 0 -> 3350 bytes .../shaders/gles/cs_update_instances.bin | Bin 0 -> 2791 bytes examples/runtime/shaders/gles/fs_particle.bin | Bin 0 -> 370 bytes examples/runtime/shaders/gles/vs_particle.bin | Bin 0 -> 885 bytes .../shaders/glsl/cs_init_instances.bin | Bin 0 -> 3347 bytes .../shaders/glsl/cs_update_instances.bin | Bin 0 -> 2788 bytes examples/runtime/shaders/glsl/fs_particle.bin | Bin 0 -> 358 bytes examples/runtime/shaders/glsl/vs_particle.bin | Bin 0 -> 825 bytes include/bgfx.h | 2 +- include/bgfxdefines.h | 1 + scripts/genie.lua | 1 + scripts/shader.mk | 2 +- src/renderdoc.cpp | 2 +- src/renderer_d3d11.cpp | 24 +- 31 files changed, 555 insertions(+), 9 deletions(-) create mode 100644 examples/24-nbody/cs_init_instances.sc create mode 100644 examples/24-nbody/cs_update_instances.sc create mode 100644 examples/24-nbody/fs_particle.sc create mode 100644 examples/24-nbody/makefile create mode 100644 examples/24-nbody/nbody.cpp create mode 100644 examples/24-nbody/screenshot.png create mode 100644 examples/24-nbody/uniforms.sh create mode 100644 examples/24-nbody/varying.def.sc create mode 100644 examples/24-nbody/vs_particle.sc create mode 100644 examples/runtime/shaders/dx11/cs_init_instances.bin create mode 100644 examples/runtime/shaders/dx11/cs_update_instances.bin create mode 100644 examples/runtime/shaders/dx11/fs_particle.bin create mode 100644 examples/runtime/shaders/dx11/vs_particle.bin create mode 100644 examples/runtime/shaders/dx9/fs_particle.bin create mode 100644 examples/runtime/shaders/dx9/vs_particle.bin create mode 100644 examples/runtime/shaders/gles/cs_init_instances.bin create mode 100644 examples/runtime/shaders/gles/cs_update_instances.bin create mode 100644 examples/runtime/shaders/gles/fs_particle.bin create mode 100644 examples/runtime/shaders/gles/vs_particle.bin create mode 100644 examples/runtime/shaders/glsl/cs_init_instances.bin create mode 100644 examples/runtime/shaders/glsl/cs_update_instances.bin create mode 100644 examples/runtime/shaders/glsl/fs_particle.bin create mode 100644 examples/runtime/shaders/glsl/vs_particle.bin diff --git a/README.md b/README.md index 7b6575b10..61471706b 100644 --- a/README.md +++ b/README.md @@ -290,6 +290,12 @@ Rendering lines as oldschool vectors. ![example-23-vectordisplay](https://github.com/bkaradzic/bgfx/raw/master/examples/23-vectordisplay/screenshot.png) +### [24-nbody](https://github.com/bkaradzic/bgfx/tree/master/examples/24-nbody) + +N-body simulation with compute shaders using buffers. + +![example-24-nbody](https://github.com/bkaradzic/bgfx/raw/master/examples/24-nbody/screenshot.png) + Dependencies ------------ @@ -717,6 +723,7 @@ p0nce ([@p0nce](https://github.com/p0nce)) - D language API bindings. Mike Popoloski ([@MikePopoloski](https://github.com/MikePopoloski)) - C#/VB/F# language API bindings, WinRT/WinPhone support. Kai Jourdan ([@questor](https://github.com/questor)) - 23-vectordisplay example +Stanlo Slasinski [@stanlo](https://github.com/stanlo) - 24-nbody example [License (BSD 2-clause)](https://github.com/bkaradzic/bgfx/blob/master/LICENSE) ------------------------------------------------------------------------------- diff --git a/examples/24-nbody/cs_init_instances.sc b/examples/24-nbody/cs_init_instances.sc new file mode 100644 index 000000000..495cdd60d --- /dev/null +++ b/examples/24-nbody/cs_init_instances.sc @@ -0,0 +1,105 @@ +/* + * Copyright 2014 Stanlo Slasinski. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + +#include "bgfx_compute.sh" +#include "uniforms.sh" + +BUFFER_WR(prevPositionBuffer, vec4, 0); +BUFFER_WR(curPositionBuffer, vec4, 1); + +uint rotl(uint _x, uint _r) +{ + return (_x << _r) | (_x >> (32u - _r) ); +} + +uint hash(uint _key, uint _seed) +{ + uint c1 = 0xcc9e2d51u; + uint c2 = 0x1b873593u; + + uint k1 = _key; + uint h1 = _seed; + k1 *= c1; + k1 = rotl(k1, 15u); + k1 *= c2; + + h1 ^= k1; + h1 = rotl(h1, 13u); + h1 = h1 * 5u + 0xe6546b64u; + k1 *= c1; + k1 = rotl(k1, 15u); + k1 *= c2; + h1 ^= k1; + + h1 ^= h1 >> uint(16u); + h1 *= 0x85ebca6bu; + h1 ^= h1 >> 13u; + h1 *= 0xc2b2ae35u; + h1 ^= h1 >> 16u; + + return h1; +} + +vec3 randomPointOnSphere(uint _id, uint _seed) +{ + uvec2 u = uvec2( + hash(_id, _seed + 0u), + hash(_id, _seed + 1u) + ); + vec2 v = uintBitsToFloat( (u >> 9u) | 0x3f800000u) - 1.0; + + float lambda = v.x * 3.14159 * 2.0; + float phi = acos(2.0 * v.y - 1.0) - 3.14159 / 2.0; + + vec3 p; + p.x = cos(lambda) * cos(phi); + p.y = sin(phi); + p.z = sin(lambda) * cos(phi); + + return p; +} + +NUM_THREADS(512, 1, 1) +void main() +{ + uint key = gl_GlobalInvocationID.x; + + vec3 position; + + if (u_initialShape == 0u) + { + position = vec3_splat(0.0); + } + else if (u_initialShape == 1u) + { + position = 20.0 * randomPointOnSphere(gl_GlobalInvocationID.x, u_baseSeed * 7u); + } + else if (u_initialShape == 2u) + { + uvec3 u = uvec3( + hash(gl_GlobalInvocationID.x, u_baseSeed * 7u + 0u), + hash(gl_GlobalInvocationID.x, u_baseSeed * 7u + 1u), + hash(gl_GlobalInvocationID.x, u_baseSeed * 7u + 2u) + ); + position = 20.0 * (uintBitsToFloat((u >> 9u) | uvec3(0x40000000, 0x40000000, 0x40000000) ) - 3.0); + } + else + { + uvec3 u = uvec3( + hash(gl_GlobalInvocationID.x, u_baseSeed * 7u + 0u), + hash(gl_GlobalInvocationID.x, u_baseSeed * 7u + 1u), + hash(gl_GlobalInvocationID.x, u_baseSeed * 7u + 2u) + ); + vec3 v = 3.14159 * 2.0 * (uintBitsToFloat( (u >> 9u) | uvec3(0x3f800000u, 0x3f800000u, 0x3f800000u) ) - 1.0); + position.x = 20.0 * cos(v.x) + 3.0 * cos(v.y) * cos(v.x); + position.y = 3.0 * sin(v.y); + position.z = 20.0 * sin(v.x) + 3.0 * cos(v.y) * sin(v.x); + } + + vec3 velocity = u_initialSpeed * randomPointOnSphere(gl_GlobalInvocationID.x, u_baseSeed * 7u + 3u); + + prevPositionBuffer[gl_GlobalInvocationID.x] = vec4(position - velocity * u_timeStep, 0.0); + curPositionBuffer[ gl_GlobalInvocationID.x] = vec4(position, 0.0); +} diff --git a/examples/24-nbody/cs_update_instances.sc b/examples/24-nbody/cs_update_instances.sc new file mode 100644 index 000000000..3ca1f9962 --- /dev/null +++ b/examples/24-nbody/cs_update_instances.sc @@ -0,0 +1,67 @@ +/* + * Copyright 2014 Stanlo Slasinski. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + +#include "bgfx_compute.sh" +#include "uniforms.sh" + +BUFFER_RO(prevPositionBuffer, vec4, 0); +BUFFER_RO(curPositionBuffer, vec4, 1); +BUFFER_WR(outPrevPositionBuffer, vec4, 2); +BUFFER_WR(outCurPositionBuffer, vec4, 3); + +#define GROUP_SIZE 512 +SHARED vec3 otherEntries[GROUP_SIZE]; + +vec3 calcAcceleration(vec3 _curPosition, vec3 _otherPosition) +{ + vec3 difference = _otherPosition - _curPosition; + float dist2 = dot(difference, difference); + float dist6 = dist2 * dist2 * dist2; + float invDist3 = 1.0 / (sqrt(dist6) + 0.1); + return u_gravity * invDist3 * difference; +} + +NUM_THREADS(GROUP_SIZE, 1, 1) +void main() +{ + vec3 prevPosition = prevPositionBuffer[gl_GlobalInvocationID.x].xyz; + vec3 curPosition = curPositionBuffer[ gl_GlobalInvocationID.x].xyz; + + vec3 newAcceleration = vec3_splat(0.0); + + for (int j = 0; j < int(u_dispatchSize); ++j) + { + otherEntries[gl_LocalInvocationIndex] = curPositionBuffer[j * GROUP_SIZE + int(gl_LocalInvocationIndex)].xyz; + + barrier(); + for (int i = 0; i < GROUP_SIZE; ++i) + { + newAcceleration += calcAcceleration(curPosition, otherEntries[i]); + } + } + + newAcceleration += (prevPosition - curPosition) * u_damping; + float accelerationMagnitude = length(newAcceleration); + float color = pow(min(accelerationMagnitude / 3.0, 1.0), 0.25); + if (accelerationMagnitude > 0.0) + { + newAcceleration = normalize(newAcceleration) * min(accelerationMagnitude, u_maxAcceleration); + } + + vec3 newPosition = 2.0 * curPosition - prevPosition + newAcceleration * u_timeStep; + + if (any(isnan(newPosition) ) ) + { + newPosition = vec3_splat(0.0); + } + + if (any(isnan(curPosition) ) ) + { + curPosition = vec3_splat(0.0); + } + + outPrevPositionBuffer[gl_GlobalInvocationID.x] = vec4(curPosition, 0.0); + outCurPositionBuffer[ gl_GlobalInvocationID.x] = vec4(newPosition, color); +} diff --git a/examples/24-nbody/fs_particle.sc b/examples/24-nbody/fs_particle.sc new file mode 100644 index 000000000..ac78c23b5 --- /dev/null +++ b/examples/24-nbody/fs_particle.sc @@ -0,0 +1,16 @@ +$input v_texCoord + +/* + * Copyright 2014 Stanlo Slasinski. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + +#include "../common/common.sh" +#include "uniforms.sh" + +void main() +{ + vec3 color = mix(vec3(0.1f, 0.8f, 0.2f), 0.5 * vec3(0.3, 0.25, 0.05), v_texCoord.z); + float f = u_particleIntensity * pow(max(1.0 - length(v_texCoord.xy), 0.0), u_particlePower); + gl_FragColor = vec4(color * f, 1.0); +} diff --git a/examples/24-nbody/makefile b/examples/24-nbody/makefile new file mode 100644 index 000000000..5ce066214 --- /dev/null +++ b/examples/24-nbody/makefile @@ -0,0 +1,17 @@ +# +# Copyright 2011-2014 Branimir Karadzic. All rights reserved. +# License: http://www.opensource.org/licenses/BSD-2-Clause +# + +BGFX_DIR=../.. +RUNTIME_DIR=$(BGFX_DIR)/examples/runtime +BUILD_DIR=../../.build + +include $(BGFX_DIR)/scripts/shader.mk + +rebuild: + @make -s --no-print-directory TARGET=0 clean all + @make -s --no-print-directory TARGET=1 clean all + @make -s --no-print-directory TARGET=2 clean all + @make -s --no-print-directory TARGET=3 clean all + @make -s --no-print-directory TARGET=4 clean all diff --git a/examples/24-nbody/nbody.cpp b/examples/24-nbody/nbody.cpp new file mode 100644 index 000000000..38f9eadb8 --- /dev/null +++ b/examples/24-nbody/nbody.cpp @@ -0,0 +1,272 @@ +/* + * Copyright 2014 Stanlo Slasinski. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + +#include "common.h" +#include "bgfx_utils.h" +#include "imgui/imgui.h" +#include "camera.h" +#include + +static const float s_quadVertices[] = +{ + 1.0f, 1.0f, + -1.0f, 1.0f, + -1.0f, -1.0f, + 1.0f, -1.0f, +}; + +static const uint16_t s_quadIndices[] = { 0, 1, 2, 2, 3, 0, }; + +int _main_(int /*_argc*/, char** /*_argv*/) +{ + uint32_t width = 1280; + uint32_t height = 720; + uint32_t debug = BGFX_DEBUG_TEXT; + uint32_t reset = BGFX_RESET_VSYNC; + + bgfx::init(); + bgfx::reset(width, height, reset); + + // Enable debug text. + bgfx::setDebug(debug); + + // Set view 0 clear state. + bgfx::setViewClear(0 + , BGFX_CLEAR_COLOR_BIT|BGFX_CLEAR_DEPTH_BIT + , 0x303030ff + , 1.0f + , 0 + ); + + void* data = load("font/droidsans.ttf"); + imguiCreate(data); + free(data); + + bgfx::VertexDecl quadVertexDecl; + quadVertexDecl.begin() + .add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float) + .end(); + + // Create static vertex buffer. + bgfx::VertexBufferHandle vbh = bgfx::createVertexBuffer( + // Static data can be passed with bgfx::makeRef + bgfx::makeRef(s_quadVertices, sizeof(s_quadVertices) ) + , quadVertexDecl + ); + + // Create static index buffer. + bgfx::IndexBufferHandle ibh = bgfx::createIndexBuffer( + // Static data can be passed with bgfx::makeRef + bgfx::makeRef(s_quadIndices, sizeof(s_quadIndices) ) + ); + + // Create particle program from shaders. + bgfx::ProgramHandle particleProgram = loadProgram("vs_particle", "fs_particle"); + + // Setup compute buffers + bgfx::VertexDecl computeVertexDecl; + computeVertexDecl.begin() + .add(bgfx::Attrib::TexCoord0, 4, bgfx::AttribType::Float) + .end(); + + const uint32_t threadGroupUpdateSize = 512; + + bgfx::DynamicVertexBufferHandle currPositionBuffer0 = bgfx::createDynamicVertexBuffer(1 << 15, computeVertexDecl, BGFX_BUFFER_COMPUTE_READ_WRITE); + bgfx::DynamicVertexBufferHandle currPositionBuffer1 = bgfx::createDynamicVertexBuffer(1 << 15, computeVertexDecl, BGFX_BUFFER_COMPUTE_READ_WRITE); + bgfx::DynamicVertexBufferHandle prevPositionBuffer0 = bgfx::createDynamicVertexBuffer(1 << 15, computeVertexDecl, BGFX_BUFFER_COMPUTE_READ_WRITE); + bgfx::DynamicVertexBufferHandle prevPositionBuffer1 = bgfx::createDynamicVertexBuffer(1 << 15, computeVertexDecl, BGFX_BUFFER_COMPUTE_READ_WRITE); + + bgfx::UniformHandle u_params = bgfx::createUniform("u_params", bgfx::UniformType::Uniform4fv, 3); + struct + { + float timeStep; + int32_t dispatchSize; + float gravity; + float damping; + float particleIntensity; + float particleSize; + int32_t baseSeed; + float particlePower; + float initialSpeed; + int32_t initialShape; + float maxAccel; + + } u_paramsData; + + u_paramsData.timeStep = 0.0083f; + u_paramsData.dispatchSize = 16; + u_paramsData.gravity = 0.069f * 0.069f; + u_paramsData.damping = 0.07f; + u_paramsData.particleIntensity = 0.35f; + u_paramsData.particleSize = 0.4f; + u_paramsData.baseSeed = 0; + u_paramsData.particlePower = 5.0f; + u_paramsData.initialSpeed = 85.0f; //112.0f; + u_paramsData.initialShape = 0; + u_paramsData.maxAccel = 30.0; + + float uiGravity = 0.069f; + + bgfx::ShaderHandle initInstancesShader = loadShader("cs_init_instances"); + bgfx::ProgramHandle initInstancesProgram = bgfx::createProgram(initInstancesShader, true); + bgfx::ShaderHandle updateInstancesShader = loadShader("cs_update_instances"); + bgfx::ProgramHandle updateInstancesProgram = bgfx::createProgram(updateInstancesShader, true); + + bgfx::setUniform(u_params, &u_paramsData, 3); + bgfx::setBuffer(0, prevPositionBuffer0, bgfx::Access::Write); + bgfx::setBuffer(1, currPositionBuffer0, bgfx::Access::Write); + bgfx::dispatch(0, initInstancesProgram, (32 * threadGroupUpdateSize) / 1024, 1, 1); + + float view[16]; + float initialPos[3] = { 0.0f, 0.0f, -25.0f }; + cameraCreate(); + cameraSetPosition(initialPos); + cameraSetVerticalAngle(0.0f); + cameraGetViewMtx(view); + + int32_t scrollArea = 0; + + entry::MouseState mouseState; + while (!entry::processEvents(width, height, debug, reset, &mouseState) ) + { + int64_t now = bx::getHPCounter(); + static int64_t last = now; + const int64_t frameTime = now - last; + last = now; + const double freq = double(bx::getHPFrequency() ); + const float deltaTime = float(frameTime/freq); + + // Set view 0 default viewport. + bgfx::setViewRect(0, 0, 0, width, height); + + // Use debug font to print information about this example. + bgfx::dbgTextClear(); + bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/24-nbody"); + bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: N-body simulation with compute shaders using buffers."); + + imguiBeginFrame(mouseState.m_mx + , mouseState.m_my + , (mouseState.m_buttons[entry::MouseButton::Left ] ? IMGUI_MBUT_LEFT : 0) + | (mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0) + , 0 + , width + , height + ); + imguiBeginScrollArea("Settings", width - width / 4 - 10, 10, width / 4, 500, &scrollArea); + imguiSlider("Random seed", u_paramsData.baseSeed, 0, 100); + u_paramsData.initialShape = imguiChoose(u_paramsData.initialShape, "Point", "Sphere", "Box", "Donut"); + imguiSlider("Initial speed", u_paramsData.initialSpeed, 0.0f, 300.0f, 0.1f); + bool reset = imguiButton("Reset"); + imguiSeparatorLine(); + imguiSlider("Particle count (x1024)", u_paramsData.dispatchSize, 1, 32); + imguiSlider("Gravity", uiGravity, 0.0f, 0.3f, 0.001f); + imguiSlider("Damping", u_paramsData.damping, 0.0f, 1.0f, 0.01f); + imguiSlider("Max acceleration", u_paramsData.maxAccel, 0.0f, 100.0f, 0.01f); + imguiSlider("Time step", u_paramsData.timeStep, 0.0f, 0.02f, 0.0001f); + imguiSeparatorLine(); + imguiSlider("Particle intensity", u_paramsData.particleIntensity, 0.0f, 1.0f, 0.001f); + imguiSlider("Particle size", u_paramsData.particleSize, 0.0f, 1.0f, 0.001f); + imguiSlider("Particle power", u_paramsData.particlePower, 0.001f, 16.0f, 0.01f); + imguiEndScrollArea(); + imguiEndFrame(); + + u_paramsData.gravity = uiGravity * uiGravity; + + float eye[3] = { 0.0f, 0.0f, -35.0f }; + float view[16]; + + // Update camera. + cameraUpdate(deltaTime, mouseState); + cameraGetViewMtx(view); + + // Set view and projection matrix for view 0. + const bgfx::HMD* hmd = bgfx::getHMD(); + if (NULL != hmd) + { + float view[16]; + bx::mtxQuatTranslationHMD(view, hmd->eye[0].rotation, eye); + + float proj[16]; + bx::mtxProj(proj, hmd->eye[0].fov, 0.1f, 10000.0f); + + bgfx::setViewTransform(0, view, proj); + + // Set view 0 default viewport. + // + // Use HMD's width/height since HMD's internal frame buffer size + // might be much larger than window size. + bgfx::setViewRect(0, 0, 0, hmd->width, hmd->height); + } + else + { + float proj[16]; + bx::mtxProj(proj, 90.0f, float(width)/float(height), 0.1f, 10000.0f); + bgfx::setViewTransform(0, view, proj); + + // Set view 0 default viewport. + bgfx::setViewRect(0, 0, 0, width, height); + } + + // Update instances + bgfx::setUniform(u_params, &u_paramsData, 3); + + if (reset) + { + bgfx::setBuffer(0, prevPositionBuffer0, bgfx::Access::Write); + bgfx::setBuffer(1, currPositionBuffer0, bgfx::Access::Write); + bgfx::dispatch(0, initInstancesProgram, (32 * threadGroupUpdateSize) / 1024, 1, 1); + } + + bgfx::setBuffer(0, prevPositionBuffer0, bgfx::Access::Read); + bgfx::setBuffer(1, currPositionBuffer0, bgfx::Access::Read); + bgfx::setBuffer(2, prevPositionBuffer1, bgfx::Access::Write); + bgfx::setBuffer(3, currPositionBuffer1, bgfx::Access::Write); + bgfx::dispatch(0, updateInstancesProgram, u_paramsData.dispatchSize, 1, 1); + + bx::swap(currPositionBuffer0, currPositionBuffer1); + bx::swap(prevPositionBuffer0, prevPositionBuffer1); + + // Set vertex and fragment shaders. + bgfx::setProgram(particleProgram); + + // Set vertex and index buffer. + bgfx::setVertexBuffer(vbh); + bgfx::setIndexBuffer(ibh); + bgfx::setInstanceDataBuffer(currPositionBuffer0, 0, u_paramsData.dispatchSize * threadGroupUpdateSize); + + // Set render states. + bgfx::setState(0 + | BGFX_STATE_RGB_WRITE + | BGFX_STATE_BLEND_ADD + | BGFX_STATE_DEPTH_TEST_ALWAYS + ); + + // Submit primitive for rendering to view 0. + bgfx::submit(0); + + // Advance to next frame. Rendering thread will be kicked to + // process submitted rendering primitives. + bgfx::frame(); + } + + // Cleanup. + cameraDestroy(); + imguiDestroy(); + bgfx::destroyUniform(u_params); + bgfx::destroyDynamicVertexBuffer(currPositionBuffer0); + bgfx::destroyDynamicVertexBuffer(currPositionBuffer1); + bgfx::destroyDynamicVertexBuffer(prevPositionBuffer0); + bgfx::destroyDynamicVertexBuffer(prevPositionBuffer1); + bgfx::destroyProgram(updateInstancesProgram); + bgfx::destroyProgram(initInstancesProgram); + bgfx::destroyIndexBuffer(ibh); + bgfx::destroyVertexBuffer(vbh); + bgfx::destroyProgram(particleProgram); + + // Shutdown bgfx. + bgfx::shutdown(); + + return 0; +} diff --git a/examples/24-nbody/screenshot.png b/examples/24-nbody/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..5212177f3052b0c803f1cf58a7cea5ad666c2d35 GIT binary patch literal 57618 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 literal 0 HcmV?d00001 diff --git a/examples/24-nbody/uniforms.sh b/examples/24-nbody/uniforms.sh new file mode 100644 index 000000000..e77698e20 --- /dev/null +++ b/examples/24-nbody/uniforms.sh @@ -0,0 +1,20 @@ +/* + * Copyright 2014 Stanlo Slasinski. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + +uniform vec4 u_params[3]; + +#define u_timeStep u_params[0].x +#define u_dispatchSize floatBitsToUint(u_params[0].y) +#define u_gravity u_params[0].z +#define u_damping u_params[0].w + +#define u_particleIntensity u_params[1].x +#define u_particleSize u_params[1].y +#define u_baseSeed floatBitsToUint(u_params[1].z) +#define u_particlePower u_params[1].w + +#define u_initialSpeed u_params[2].x +#define u_initialShape floatBitsToUint(u_params[2].y) +#define u_maxAcceleration u_params[2].z diff --git a/examples/24-nbody/varying.def.sc b/examples/24-nbody/varying.def.sc new file mode 100644 index 000000000..c2bead997 --- /dev/null +++ b/examples/24-nbody/varying.def.sc @@ -0,0 +1,4 @@ +vec2 a_position : POSITION; +vec4 i_data3 : TEXCOORD7; + +vec3 v_texCoord : TEXCOORD0 = vec3(0.0, 0.0, 0.0); diff --git a/examples/24-nbody/vs_particle.sc b/examples/24-nbody/vs_particle.sc new file mode 100644 index 000000000..329bcc497 --- /dev/null +++ b/examples/24-nbody/vs_particle.sc @@ -0,0 +1,23 @@ +$input a_position, i_data3 +$output v_texCoord + +/* + * Copyright 2014 Stanlo Slasinski. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + +#include "../common/common.sh" +#include "uniforms.sh" + +void main() +{ + vec3 eye = mul(u_view, vec4(i_data3.xyz, 1.0) ).xyz; + vec3 up = normalize(cross(eye, vec3(1.0, 0.0, 0.0) ) ); + vec3 right = normalize(cross(up, eye)); + float size = u_particleSize; + vec3 position = eye + size * right * a_position.x + size * up * a_position.y; + + v_texCoord.xy = a_position; + v_texCoord.z = i_data3.w; + gl_Position = mul(u_proj, vec4(position, 1.0) ); +} diff --git a/examples/makefile b/examples/makefile index d1ac5b744..dd33cb196 100644 --- a/examples/makefile +++ b/examples/makefile @@ -26,6 +26,7 @@ rebuild: # @make -s --no-print-directory rebuild -C 20-nanovg @make -s --no-print-directory rebuild -C 21-deferred @make -s --no-print-directory rebuild -C 23-vectordisplay + @make -s --no-print-directory rebuild -C 24-nbody @make -s --no-print-directory rebuild -C common/font @make -s --no-print-directory rebuild -C common/imgui @make -s --no-print-directory rebuild -C common/nanovg diff --git a/examples/runtime/shaders/dx11/cs_init_instances.bin b/examples/runtime/shaders/dx11/cs_init_instances.bin new file mode 100644 index 0000000000000000000000000000000000000000..23b42a9c50276e921193906b74b3c9fc45470c52 GIT binary patch literal 6767 zcmeHMO=z4&7=Cy5Cz~(Uq>&1)&@KrmEDAMPk)UR>)!5=+OKfdVwZ(&26j{-$Yy1Nd z4+^3vQnUuV^x#=-%t2`JQ1B#PJoTb@@GRon4RyN_y1?!nQ!*s z@}ZKUm8|~aspn63PCxrXwY)zo+mXioC)x+UeyLUd@y{Rj?ETGM_eJTAapE3nn3XZ! zhJFwF!{~>XAAGcqk&WYHh4}ef9LWVMaoh!%aOWfKEc_x|!HCNkaeV6R<5yEztw=|hY?og&$C0)RSF&Jxowf^K zaN^VM)Ly}|C@^#Y&?7Um)8gJrLT6%_rQfO*9Y-U^+ozyQQujF zNV@jRQQFLWPjzcVAIWCQo+-?cZrI!qKj?DJ+(`9k6=V+5BlSVPb_;aF#H^ov#hA$s z`DHu4idjFt(w8vCtjHI3W^>VorHJF;?{VO=tL-h|(RSzYW8H<&`JA^c{1Uv2z(Wu1 z?xa4*M#lNdl(+OCJ*~NPPfkRmGMki1*3STHcJU9DL|==BepQXu`YQ58Jf_}_bgOSQ5e+k*{hY@_!l=e) z=R-}vW8Rqa+~?*Zz0Pdk#dp>JGVoac8EfZ5elSPWa4y>|9?ti|ImcXLR}(*u>fDJwN^7Y0dF}Pw=Tki816cZ` z<8ct4Uju6Fy|sIjpXxTpP`eR>(RU7fq1vE2fOV6f5$HR?N`6$2xz5rvy!<5}A)oSZ zw&|Gnny2q{X5OwIx8qtW@cR`yAKM z`?$9tj`J)yp<~F~zwn*Y_j`!nIqXp^&(byCFRVv@9FKLIXJ76~)K`0m%c)p5ef|WH z={thYw4L~^$cuT;cgi3y`hc>u$5F=l{hauxvqC`uaocl>yekv77o1Bbgz}}=faZ@ zm0$F;=A7?6C;iiN6#2uiJ3dE2&yBl4#*BU)#&5!vueDAU8_koK?!z`>UpQ;gSMqmn zzJ;@z*0Xph_vKs2|6iQf2HB^4Vtiz?gKz(XdbM$H%etZb7~RW+b%JoLF~>*uGWprQ z-ibM)Z;D#C2^WR`L9ky;B=GJc=9y2z`3%pbW8=M#>N)+(hHu>3@9}?`8g{Uy>q9;Y SmpDb-oPWe6{Jvb|li6QYOUvv4 literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx11/cs_update_instances.bin b/examples/runtime/shaders/dx11/cs_update_instances.bin new file mode 100644 index 0000000000000000000000000000000000000000..8bc43b90a90bdd09c72ef9e92fbd45e34638e066 GIT binary patch literal 1731 zcmZvc%}Z2K7{=dw@60$3rjF2;MA%k}te`K-ZfcWJlwgLf%v}V5C~ZSp8ANTQO)dhb z5?i+l`U`9uEu(ddaN)Y=ckg+}!_a|q-*cYl{eBO3a&|f~t;Fij7M2#57oVoJ_t(&E*UU1>liF9b?`Yqey?M7T$wJ=iy3bDEn4gi| zj8$!2PM*{)d1zK?y&l2DK5Ea`tzt`q#eHsW|4vNq8}PrHmUi9A1%AOq@bbPFP zRor`1(7#Qc%=-Aq!8^r9;+uWSY;D49b#m^YEnAsGO$x2&<++>3#(B=?RW^3ymgf3& zE%DVC!Ech6YG_51BZWQ)^J^X92SP`m2}%io>I%pxRy-( z-azStddPQ+d_zyL!4IpI4i>ZhcEl2LrY7vc$-(R3>^7l}9&$t1^DTHOdJS-&lrBCi z-FmvWcFP&*So9Jd#a+EFNzUW|ripZ7Ip*?W;M~9GgLE#&$Q9k&VLmY@xDy9GxFk3G zzO!?+Kg?1aUiynJC^km!Vweo8Cdv>3DZ$?nFO>HpZ`7FR4bLlL!p;(EuXiy z$InGvBkDJOJ+1k;opZ4-$EZ>I<42=;I(H`cXWpgWem|#zKGx*L!vAlb(PuWST5nmm zaxLZx=5_d7KM4Du?SuZ(*M%^1`ce!2-}aQ8_fGvkK>t}_3@pv{G2`pIGc#f4Gvn-j zYSCK*V_i~R@od4I)Bn79^I*e@Pmc5t8FQln^IoZ@K78_?yjN+iOV{!^{vV+(pG8~k Y*bV>p;@_%%!8?v`$2pG|@Ay&UA4p+{a{vGU literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx11/fs_particle.bin b/examples/runtime/shaders/dx11/fs_particle.bin new file mode 100644 index 0000000000000000000000000000000000000000..f32c363f5023fe09028c4d6321a0c92353bdd423 GIT binary patch literal 603 zcmZ<@_F&Eu+qILCful6OAh9Shw^)?ffQy;IhRG$u$$8JuN$yW>Wft82HmP&Htj|G4 z1_q!E0|PUV)&b%cAl?DQp26;Z0YDlk#lQi?7C;OFAoU=%AixjAE?^df0EvU-+1VKw zg2Uni{DVD1JpKI`LR=%9{r!Vn7*?-d?GH2;WDiIk$Xo>=h5=-Af%-!ngWO$1fSQ6m zT!LzV8XSNM^C+x-iHu70~GVI2Vy&* fd)SMhVZ;VCV;Vaoe9VAuX@bhZ{A&k}t^_UsSRF?j literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx11/vs_particle.bin b/examples/runtime/shaders/dx11/vs_particle.bin new file mode 100644 index 0000000000000000000000000000000000000000..23d163e61eaa397fd7317392c62518ae2d3da9a9 GIT binary patch literal 1149 zcmaJFkMX-T2;zC-M`9jzhh~nWOvv^pcm< zo9vaWk?aM{`Qba;UVLLN_T(DnP&fY!mvVTgzI~S%vmIdeua3jvY!uf&>>-}9GY_WT yW=LK#e*#X|voXs&coF%+#$u~6vdmqNuY^-em@n?RK)R@f5k@pJEb7x2Z literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/dx9/fs_particle.bin b/examples/runtime/shaders/dx9/fs_particle.bin new file mode 100644 index 0000000000000000000000000000000000000000..979449435ac726093c1911459b2d5a28f624d35a GIT binary patch literal 404 zcmYjN%SyvQ6g`u%CLriaSAxNnf`q2QML;cDkS^jv*eGXpa6GFIzCF+T(jB!f8@;9;^obK7@9)r7 zhY4U7H=qFs=JP_sfGW+#w$_lZ{>%9mT5a^HWZfFMXnC&h*^6`jhg^_z#Bb6r9`TKxnSBGLgbU8zP_ul~EfCEEF+zg!mC58Vn#d7He;DiJjHe+%M4D zhR*m4DDHQ7&fA4(baOB7z1exQvwJ7ay6!E%y=pAowQoCv&dt!*OHjzN9rSy7FN2IU zpnWV=f@XU0|P!KiXoFQw(P*lk>LFClTj?2KRvuA)Hl-ftmc=MVZ!DkK!@!ZVk zYrt}n$U`gSz4+zGlO7?nSzyXy6N~W;?40at;-W)6&V8B!J|dZM{gnMXwUWm*`cdSt zHb4BSQJh)u6{c20_`(rB&oz0pBAM5J=6SZ=lll2QIRDQ#v6l7i&JCoehh*+E;Q2|! lIqS`71tx2;iN)M~gPGhnN1Sh?_^+i8U7eYENW(Ox$~PJ1gKPi* literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/gles/cs_init_instances.bin b/examples/runtime/shaders/gles/cs_init_instances.bin new file mode 100644 index 0000000000000000000000000000000000000000..92cc0d8e8b79a6ee6bcc3c72c974e316c03f6ae9 GIT binary patch literal 3350 zcmd^BOK;mo5Oz-m2=qS;&G_-1wVs@*JB)VeCcZQJfa#&sAc| zhXDU0+J>b^!M3a|x~E)}Ri2VbCMzvE$3d#B89kgrw08QU*{P~X>;R>6bU~v^}D838n3f_%LVqS3ih%1{9Z)m%otF76tzf>8d(_S(i6t%{x?AN zO|M^*>A4kMNSQS=9t`QV35$&ex)p~8st{tuXwoEdXijz=MOVUIO`Hln;1sYd zEOwTcFTKf?*NAV~Isle7+sJ1IoEgxa&na@`X|67D>x{^mRLDqc-I)QO-{*7-JLxSi zyJ0(z?W7EU=QOG4JES0{6Mwp#`bgnlML;aTp+bBw)0yfZNY$<{Ct?|e(pOWCmBwL2byL1nHW{-Do$F(doZlwujX2fe!?;KU}UwN#m zKvR{w7#}Q}W4O?wd!z9JJlDpw@w(xQh@=qoWkB5P6Cf8LsOQk6J#mE*$$k&z>nz51 z+?|)a7XK(OSLVf&>$NlN=^1`b9w$@(Od!-wug^1q__92?dI-=?-37Va-PP-Eo-B@O z*S_378?UY5vqfr`jN!P5OWy7DL&YvUfGf||iWHLg{WP9M*((^8$* zsu*xfb?U2@f-j|78G@%!CL7M~zp_-%20aJg*_P#p6HAOU=?J;l{6wgZe68eNM~KQ- zeR2~_??Hv$d$y7p%jfZA(Q#u>dZXH(G!b3p%7o_YTl$qP4~P|8YpUp~n8)ZVr#o3{ zQs`_NMWW8h`g5_j`ZaP8p#)vbOJzLgl)+ zrHW;43rT&;)O(>7XT|({Y#PnXAEY!-U#BU{nWCn))duvqtk;-DsOu379-V#0O?xnr zGPs1Kp#v`<@o;7X*O?hF^aPbNsmZ}Qgu`>-t6msYYjWEBu9a}C-r;$SdboGs3`p@y z8R$Y^1TchXG)BN`ftN|u{n29dfLnZTY{2VGW`n0{GJxa~8A=NNz>+O`K;}a5WIN-v zA$c&80D+NU$uqo0xFCDF{HZ`i|J6;^{3cI6n+ucK5vqO_0 zhDUJ)0sny^*u7tN#Ifr*!p)7uN(F=q4Rs|O4P^DB?!D>X^x%W2?+B# z>OVZBJi!^W#Mw=QS=HMEbC}?$p88}Vbqywm(4wJ5=C;a8>3L literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/gles/fs_particle.bin b/examples/runtime/shaders/gles/fs_particle.bin new file mode 100644 index 0000000000000000000000000000000000000000..a35ea3a58938bd01d15c34fb5d0e054a4a77db11 GIT binary patch literal 370 zcmY+9&r8EF6vs1qQ1SrF-pc6O1asae;i6aO&%>wFn>WtY70 zdA#qB^~-bedH44_Be%z*(O%obO+rXQUT1`K+7G6#U}vgb1Ksw04qef1!^$~d=JZ&b z59e)MEMUBTn{RU3Ia7kwrUu68H-$-I0j+INw@^9a@h^IK0wv@X3&RO1vnBwG-b@OW zf)tPO$#{AW6yY)gm7RyomT_}QDNY>jfnCz6jR*)D*8{@z&R^4=2sZuvpgxrQCjsix+Awbm+Yrn4J@GwXT z3*_<4c?6a2Oh1MWHhu2mRCI8=w=E7&65h-izbCx$47Y$$2i^m!zzsHn5215X5Z)yz(S f8rSwvXIxn|OgH=JwS59gdGm;LSAgJuEX()@_;3~D literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/glsl/cs_init_instances.bin b/examples/runtime/shaders/glsl/cs_init_instances.bin new file mode 100644 index 0000000000000000000000000000000000000000..b8ea84ad39213250e84b4b5bdb2a84878d08933e GIT binary patch literal 3347 zcmd^BOK;mo5O#r{2=qS;&G_-1wVs@;%$wi^!umEy|y(#FP&K z{ztS8OOJwWSzB~ZxhShVC6i26T6B(sR9Q26IE85aM%1D`f{>mJA+Z_=zng_mZ5B9w zX%{Au&WAXXDh{~BUp!g_iksLL$Fv_JTjMM#Zfa=M2 zdG<$72;=J^IVUry(CCA@ZMG80jpr_UVWeg-t5$Q0s5(~#VY1tV@5TCvsH?RL^Ke_- zc!-sRhpZ~iqFiAUMzoC6Rh)jB+ZKJ!<5Fa4a-e0kUW=S|x!7N4MO#(ds-c_ic?H=RwkxA1@(y3A-9ZsquK4CrdO{h$SwL4 zt69_Q*JOHbMHf_dTqjDqk(S4p@AxdSTUM3i5!}fT}RQCa90zjLJv3vEDMXB z<>gCna^*GRTec2>rOh_-nE_`8bmw!59C@0nOWZmmawZir(pq&uB)M&Wb`Y}mAx$V3XH zP2?`!PFE+>eZhah$>XH;*)8}b_Hx0 za7p?4l{Fd=JC$XiR?>gZ{s{LbE{l)Z4@`^T{)%sWRq=q>wYR>s`G>~~0^`jLwRuUn zU9Lj-@5eO??u{ManOx!I9&L7;7zSaK6(*$6?Z*d&!eEWd3*~}@Jlf5S9q=#;@KGW7 zEyPa%L)tqa%&Cae_W4df4_WIP1NA|Z0GUY^g-KAvcLKvdr-|c^s3T)|3{*$L0kE}k zilSxl3U5qAZ+8Im4E?7h_%X?rVe&5B1E1OB-P>_3%ZyuTLYW!yn$$Z-Rs2^Tt18e` zSnV_#z@H1brD0_xc3L1qkXnG-*#ODwo4vMYBEh2I9du`wQ_QzoUzbA9q}pqL4I?r=uNDV-m8|pQ}8uFA4rf zv|&1?WTW>Xy^!L%Qj!7+%wb5Ec(6y|f?nGYN4toQXdMV^X&@|C12OlbnA0%|JbrH! zCkRC0>}(Vc?f;`#=LOTG(rw_L66V=lPo`H1tMi>%EyO>gmXeVK&;!-M!c)B%4IF&sd!C<8EHTccClqq`H=ug*ttuXS zLMY!3$xSeW2Q~WO*`~;NzKmz9o*R2I7}fEljp!;@B`n`QurGXlLaf=^GQ~FKGKR05 z9g0c^rOq%35#0%y33-1r4bku{D`bA4yK24WinfaHZi`ZAjLkbM>PwvFi>pfic)3FF zob`F#_nB6z?Xo9mdF-8j+u|HMwkmH%b_*4>*sZhrL5r z6qNrc16}I3A&qG|xdvdpz^kP0{^@G+j4ggNHsDPri_vR685HCN7)na<%#%GlfVqe~ z*}-^iNuG@)1TY9LM22fb$lyqqKNV2)U)@wK@AKsMytrfeN4bM-2JSPvmqJ&WnV+1?d;Jh} zyqNUty_^;~3WKgGo`Ma!Y8d8<;t6)Sxq~A#|LhIy#hT7&{{ofi5JNX4al^74o!<)x zd7bqiol>4*#w>Am(;%y6dmx7yM)lGs3)Hok98-se4w?HpD|rY+DVa1uHuxdo z;L>aGSI5ZFwpBD|>xsIy!|VRs&^haQ-~pPtm^m9-?#r{&+W>iqMr3=!l6>(W{DHkX literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/glsl/fs_particle.bin b/examples/runtime/shaders/glsl/fs_particle.bin new file mode 100644 index 0000000000000000000000000000000000000000..0140c3d8982513725360343623b108244858ea89 GIT binary patch literal 358 zcmY+9&uhXk6vrbyY~&Bv`5lu{LsBOU%1(lK_c)}4)s+m>bg{On;vcsCb$fAC@sfnk z%lrOVu2;#|)9=rOJRXWhdu{g*2_XqtO$h0L3S-Nho+%}NYS?G` literal 0 HcmV?d00001 diff --git a/examples/runtime/shaders/glsl/vs_particle.bin b/examples/runtime/shaders/glsl/vs_particle.bin new file mode 100644 index 0000000000000000000000000000000000000000..39f9df50dcd38b972db24c1fa0cfd854a32d41a9 GIT binary patch literal 825 zcmZuwO;3YB5Z#8v4}O5>IYOKGL=Io(ben^3UN)wT(4Fc7&&57!oB7MtK(Xr0TCqfVem zK9?Y(y*fxORTkQ#k`FS9g%)0D7b34@wxI?OibyBrlTvvc+Q&?;Rh~jBv=5Dle@PNE zByj{G8&U7x3WqBh;{cg~%?)KZZfax66X+`Gw1UeiJJkQTo)c-fYoI+ zf^}FIAEH_Bl+c|V-yrspxHoID;uY0~3qainFmG^FHH|r)I}K+8gC@A(Y(S=vUHuwx z4-V2pznG6pU9iP#ZRuUY^-VuK-uThi(M58CW>1Z6IA)2n6F_urkLQk&RpaAk7rnF} RGbwL=grO@yv%hVd{Q+kv|F{4E literal 0 HcmV?d00001 diff --git a/include/bgfx.h b/include/bgfx.h index d3d490b18..2d99a411b 100644 --- a/include/bgfx.h +++ b/include/bgfx.h @@ -14,7 +14,7 @@ /// #define BGFX_HANDLE(_name) \ struct _name { uint16_t idx; }; \ - inline bool isValid(_name _handle) { return bgfx::invalidHandle != _handle.idx; } + inline bool isValid(_name _handle) { return bgfx::invalidHandle != _handle.idx; } #define BGFX_INVALID_HANDLE { bgfx::invalidHandle } diff --git a/include/bgfxdefines.h b/include/bgfxdefines.h index 8c1666b8c..cbdca2774 100644 --- a/include/bgfxdefines.h +++ b/include/bgfxdefines.h @@ -198,6 +198,7 @@ #define BGFX_BUFFER_COMPUTE_NONE UINT8_C(0x00) #define BGFX_BUFFER_COMPUTE_READ UINT8_C(0x01) #define BGFX_BUFFER_COMPUTE_WRITE UINT8_C(0x02) +#define BGFX_BUFFER_COMPUTE_READ_WRITE (BGFX_BUFFER_COMPUTE_READ | BGFX_BUFFER_COMPUTE_WRITE) /// #define BGFX_TEXTURE_NONE UINT32_C(0x00000000) diff --git a/scripts/genie.lua b/scripts/genie.lua index 03b93e82a..10a79502f 100644 --- a/scripts/genie.lua +++ b/scripts/genie.lua @@ -310,6 +310,7 @@ exampleProject("20-nanovg") exampleProject("21-deferred") exampleProject("22-windows") exampleProject("23-vectordisplay") +exampleProject("24-nbody") if _OPTIONS["with-shared-lib"] then group "libs" diff --git a/scripts/shader.mk b/scripts/shader.mk index 2aa09a305..588c56a7c 100644 --- a/scripts/shader.mk +++ b/scripts/shader.mk @@ -26,7 +26,7 @@ else ifeq ($(TARGET), 1) VS_FLAGS=--platform windows -p vs_4_0 -O 3 FS_FLAGS=--platform windows -p ps_4_0 -O 3 -CS_FLAGS=--platform windows -p cs_5_0 -O 3 +CS_FLAGS=--platform windows -p cs_5_0 -O 1 SHADER_PATH=shaders/dx11 else ifeq ($(TARGET), 2) diff --git a/src/renderdoc.cpp b/src/renderdoc.cpp index c487eb1e6..ccf75b926 100644 --- a/src/renderdoc.cpp +++ b/src/renderdoc.cpp @@ -5,7 +5,7 @@ #include "bgfx_p.h" -#if BGFX_CONFIG_DEBUG_PIX && (BX_PLATFORM_WINDOWS || BX_PLATFORM_LINUX) +#if BGFX_CONFIG_DEBUG_PIX && !BGFX_CONFIG_RENDERER_OPENGLES && (BX_PLATFORM_WINDOWS || BX_PLATFORM_LINUX) # if BX_PLATFORM_WINDOWS # include # endif // BX_PLATFORM_WINDOWS diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index 4d360d8cb..b467375c6 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -40,6 +40,17 @@ namespace bgfx }; BX_STATIC_ASSERT(BX_COUNTOF(s_primInfo) == BX_COUNTOF(s_primName)+1); + union Zero + { + ID3D11Buffer* m_buffer[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; + ID3D11UnorderedAccessView* m_uav[D3D11_PS_CS_UAV_REGISTER_COUNT]; + ID3D11ShaderResourceView* m_srv[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; + ID3D11SamplerState* m_sampler[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; + uint32_t m_zero[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; + }; + + static Zero s_zero; + static const uint32_t s_checkMsaa[] = { 0, @@ -3161,13 +3172,14 @@ namespace bgfx { wasCompute = true; - ID3D11ShaderResourceView* srv[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS] = {}; - deviceCtx->VSSetShaderResources(0, BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, srv); - deviceCtx->PSSetShaderResources(0, BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, srv); + deviceCtx->IASetVertexBuffers(0, 2, s_zero.m_buffer, s_zero.m_zero, s_zero.m_zero); + deviceCtx->IASetIndexBuffer(NULL, DXGI_FORMAT_R16_UINT, 0); - ID3D11SamplerState* sampler[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS] = {}; - deviceCtx->VSSetSamplers(0, BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, sampler); - deviceCtx->PSSetSamplers(0, BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, sampler); + deviceCtx->VSSetShaderResources(0, BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, s_zero.m_srv); + deviceCtx->PSSetShaderResources(0, BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, s_zero.m_srv); + + deviceCtx->VSSetSamplers(0, BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, s_zero.m_sampler); + deviceCtx->PSSetSamplers(0, BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, s_zero.m_sampler); } const RenderCompute& compute = renderItem.compute;