Skip to content

Commit

Permalink
Update README.md and make GL interface possible to use externally.
Browse files Browse the repository at this point in the history
  • Loading branch information
Hans-Kristian Arntzen committed Nov 12, 2015
1 parent 6017bd5 commit 2bb65d0
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 34 deletions.
62 changes: 45 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@ graphics use cases.
### Platform support

Desktop Linux and Windows have been tested and are supported. Supports both OpenGL 4.3 core and OpenGL ES 3.1.
Should work on Android devices with GLES 3.1, but this has not been tested yet.

The GLSL code has been tested and verified on:

- ARM Mali T-760 (Linux)
- ARM Mali T-760 (Linux, Android 5.x)
- nVidia GTX 760 (Linux)
- Intel HD 4400 (Windows 7 x64)

Expand All @@ -56,11 +55,15 @@ GLFFT is a performance oriented FFT library, and aims to reach optimal efficienc

## Integrating GLFFT into a code base

Due to the nature of OpenGL, it is not always feasible to build GLFFT as a standalone library, as applications
might have their own ways of getting to OpenGL symbols and headers which is not easy for GLFFT to work with.

Comprehensive virtual interfaces to abstract all dependencies on OpenGL would have been possible, but for ease and simplicity, this was avoided.
GLFFT is an OpenGL oriented implementation, but all API specifics of GLFFT have been abstracted away to
make it suitable for integration into engines which might have abstracted interfaces to the underlying graphics APIs.
It is possible to implement GLFFT without OpenGL, as long as GLSL is supported as a shading language,
which is assumed to be feasible once SPIR-V becomes mainstream.
The abstracted interface is designed to match the spirit of next-generation APIs like Vulkan and D3D12.

As using GLFFT in a GL context is by far the most common use case, a default, ready-to-go OpenGL interface
is supplied in the API. Due to the nature of OpenGL, it is not always feasible to build GLFFT as a standalone library, as applications
might have their own ways of getting to OpenGL symbols and headers which is not easy for GLFFT to work with.
Instead, the GLFFT implementation will include a user-supplied header, `glfft_api_headers.hpp` which is responsible for including
the appropriate OpenGL or OpenGL ES 3.1 headers (or special headers like GLEW) the calling application uses,
as well as defining various constants, such as the GLSL language strings to use.
Expand All @@ -85,7 +88,7 @@ When compiling, C++11 must be enabled, and `glfft_api_headers.hpp` must be found
### Do a 1024x256 Complex-To-Complex FFT.

#include "glfft.hpp"
#include "glfft_api_headers.hpp"
#include "glfft_gl_interface.hpp"
#include <memory>

using namespace GLFFT;
Expand All @@ -97,18 +100,29 @@ When compiling, C++11 must be enabled, and `glfft_api_headers.hpp` must be found
options.type.output_fp16 = true; // Use FP16 output.
options.type.normalize = true; // Normalized FFT.

FFT fft(1024, 256, ComplexToComplex, Inverse, SSBO, SSBO, make_shared<ProgramCache>(), options);
GLContext context;

FFT fft(&context, 1024, 256, ComplexToComplex, Inverse, SSBO, SSBO, make_shared<ProgramCache>(), options);

GLuint output_ssbo, input_ssbo;
// Create GL_SHADER_STORAGE_BUFFERs and put some data in them.
fft.process(output_ssbo, input_ssbo);
glMemoryBarrier(GL_ALL_BARRIER_BITS);

// Adapt raw GL types to types which GLContext uses internally.
GLBuffer adaptor_output(output_ssbo);
GLBuffer adaptor_input(input_ssbo);

// Do the FFT
CommandBuffer *cmd = context.request_command_buffer();
fft.process(cmd, &adaptor_output, &adaptor_input);
context.submit_command_buffer(cmd);

glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);

### Do a 1024x256 Complex-To-Complex FFT more optimally using wisdom.

#include "glfft.hpp"
#include "glfft_wisdom.hpp"
#include "glfft_api_headers.hpp"
#include "glfft_gl_interface.hpp"
#include <memory>

using namespace GLFFT;
Expand All @@ -120,29 +134,43 @@ When compiling, C++11 must be enabled, and `glfft_api_headers.hpp` must be found
options.type.output_fp16 = true; // Use FP16 output.
options.type.normalize = true; // Normalized FFT.

GLContext context;

FFTWisdom wisdom;
// Use some static wisdom to make the learning step faster.
// Avoids searching for options which are known to be bogus for a particular vendor.
wisdom.set_static_wisdom(FFTWisdom::get_static_wisdom_from_renderer(reinterpret_cast<const char*>(glGetString(GL_RENDERER))));
// Learn how to do 1024x256 much faster!
wisdom.learn_optimal_options_exhaustive(1024, 256, ComplexToComplex, SSBO, SSBO, options.type);
wisdom.learn_optimal_options_exhaustive(&context, 1024, 256, ComplexToComplex, SSBO, SSBO, options.type);

GLContext context;

// Create a FFT, with added wisdom.
FFT fft(1024, 256, ComplexToComplex, Inverse, SSBO, SSBO, make_shared<ProgramCache>(), options, wisdom);
FFT fft(&context, 1024, 256, ComplexToComplex, Inverse, SSBO, SSBO, make_shared<ProgramCache>(), options);

GLuint output_ssbo, input_ssbo;
// Create GL_SHADER_STORAGE_BUFFERs and put some data in them.
fft.process(output_ssbo, input_ssbo);
glMemoryBarrier(GL_ALL_BARRIER_BITS);

// Adapt raw GL types to types which GLContext uses internally.
GLBuffer adaptor_output(output_ssbo);
GLBuffer adaptor_input(input_ssbo);

// Do the FFT
CommandBuffer *cmd = context.request_command_buffer();
fft.process(cmd, &adaptor_output, &adaptor_input);
context.submit_command_buffer(cmd);

glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);

### Serializing wisdom to a string

GLContext context;

FFTWisdom wisdom;
// Use some static wisdom to make the learning step faster.
// Avoids searching for options which are known to be bogus for a particular vendor.
wisdom.set_static_wisdom(FFTWisdom::get_static_wisdom_from_renderer(reinterpret_cast<const char*>(glGetString(GL_RENDERER))));
// Learn how to do 1024x256 much faster!
wisdom.learn_optimal_options_exhaustive(1024, 256, ComplexToComplex, SSBO, SSBO, options.type);
wisdom.learn_optimal_options_exhaustive(&context, 1024, 256, ComplexToComplex, SSBO, SSBO, options.type);

// Serialize to string.
string wisdom_json = wisdom.archive();
Expand Down
8 changes: 4 additions & 4 deletions android/android.iml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="android" external.linked.project.path="/1tbdisk/git/GLFFT/android" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<module external.linked.project.id="android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="/1tbdisk/git/GLFFT/android/build" />
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
<exclude-output />
<content url="file:///1tbdisk/git/GLFFT/android">
<excludeFolder url="file:///1tbdisk/git/GLFFT/android/.gradle" />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
Expand Down
8 changes: 4 additions & 4 deletions android/app/app.iml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="/git/GLFFT/android" external.system.id="GRADLE" external.system.module.group="android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
Expand Down Expand Up @@ -92,9 +92,9 @@
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="recyclerview-v7-23.1.0" level="project" />
<orderEntry type="library" exported="" name="support-v4-23.1.0" level="project" />
<orderEntry type="library" exported="" name="design-23.1.0" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-23.1.0" level="project" />
<orderEntry type="library" exported="" name="support-annotations-23.1.0" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-23.1.0" level="project" />
<orderEntry type="library" exported="" name="design-23.1.0" level="project" />
<orderEntry type="library" exported="" name="support-v4-23.1.0" level="project" />
</component>
</module>
20 changes: 12 additions & 8 deletions glfft_gl_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,16 @@ void GLContext::unmap(Buffer *buffer)
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
}

void GLContext::teardown()
{
if (initialized_ubos)
glDeleteBuffers(MaxBuffersRing, ubos);
initialized_ubos = false;
}

GLContext::~GLContext()
{
// The backing context has already died, so no need to free GL resources manually.
//glDeleteBuffers(MaxBuffersRing, ubos);
teardown();
}

GLTexture::GLTexture(const void *initial_data,
Expand All @@ -262,7 +268,8 @@ GLTexture::GLTexture(const void *initial_data,

GLTexture::~GLTexture()
{
glDeleteTextures(1, &name);
if (owned)
glDeleteTextures(1, &name);
}

GLBuffer::GLBuffer(const void *initial_data, size_t size, AccessMode access)
Expand All @@ -275,7 +282,8 @@ GLBuffer::GLBuffer(const void *initial_data, size_t size, AccessMode access)

GLBuffer::~GLBuffer()
{
glDeleteBuffers(1, &name);
if (owned)
glDeleteBuffers(1, &name);
}

GLProgram::GLProgram(GLuint name)
Expand All @@ -290,10 +298,6 @@ GLProgram::~GLProgram()
}
}

GLSampler::GLSampler(GLuint name)
: name(name)
{}

GLSampler::~GLSampler()
{
if (name != 0)
Expand Down
10 changes: 9 additions & 1 deletion glfft_gl_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,26 +53,29 @@ namespace GLFFT
friend class GLCommandBuffer;
~GLTexture();

GLTexture(GLuint obj) : name(obj), owned(false) {}
GLuint get() const { return name; }

private:
GLTexture(const void *initial_data,
unsigned width, unsigned height,
Format format);
GLuint name;
bool owned = true;
};

// Not really used by test and bench code, but can be useful for API users.
class GLSampler : public Sampler
{
public:
friend class GLContext;
friend class GLCommandBuffer;
~GLSampler();

GLSampler(GLuint obj) : name(obj) {}
GLuint get() const { return name; }

private:
GLSampler(GLuint name);
GLuint name;
};

Expand All @@ -83,11 +86,13 @@ namespace GLFFT
friend class GLCommandBuffer;
~GLBuffer();

GLBuffer(GLuint obj) : name(obj), owned(false) {}
GLuint get() const { return name; }

private:
GLuint name;
GLBuffer(const void *initial_data, size_t size, AccessMode access);
bool owned = true;
};

class GLProgram : public Program
Expand Down Expand Up @@ -165,6 +170,9 @@ namespace GLFFT
bool supports_texture_readback() override { return false; }
void read_texture(void*, Texture*, Format) override {}

protected:
void teardown();

private:
static GLCommandBuffer static_command_buffer;

Expand Down
5 changes: 5 additions & 0 deletions glfft_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ namespace GLFFT
{
public:
virtual ~Resource() = default;

// Non-movable, non-copyable to make things simpler.
Resource(Resource&&) = delete;
void operator=(const Resource&) = delete;

protected:
Resource() = default;
};
Expand Down
2 changes: 2 additions & 0 deletions test/android/jni.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ struct AndroidEGLContext : GLContext
{
if (dpy)
{
teardown();

eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (ctx)
eglDestroyContext(dpy, ctx);
Expand Down
1 change: 1 addition & 0 deletions test/glfw/glfw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ struct GLFWContext : GLContext
{
if (window)
{
teardown();
glfwDestroyWindow(window);
glfwTerminate();
}
Expand Down

0 comments on commit 2bb65d0

Please sign in to comment.