blob: 216c1701b2414ceca77ee3927d4aab3f5148a7f3 [file] [log] [blame]
#include "stdlib.h"
#include "radfnptrinit.h"
#include "string.h"
#ifdef _WIN32
#include <windows.h>
#endif
#ifdef __linux__
#include <GL/glx.h>
#endif
#include <stdio.h>
#include <time.h>
#include <RAD/rad.h>
#include <EGL/egl.h>
RADdevice device;
RADqueue queue;
bool useCopyQueue = false /*true*/;
RADqueue copyQueue;
#define SHADER_SOURCE(source) #source
static const char *vsstring =
//"#version 440 core\n"
//"#define BINDGROUP(GROUP,INDEX) layout(binding = ((INDEX) | ((GROUP) << 4)))\n"
//"layout(location = 1) in vec4 tc;\n"
//"layout(location = 0) in vec4 position;\n"
//"BINDGROUP(0, 2) uniform Block {\n"
//" vec4 scale;\n"
//"};\n"
//"out vec4 ftc;\n"
//"void main() {\n"
//" gl_Position = position*scale;\n"
//// This line exists to trick the compiler into putting a value in the compiler
//// constant bank, so we can exercise binding that bank
//" if (scale.z != 1.0 + 1.0/65536.0) {\n"
//" gl_Position = vec4(0,0,0,0);\n"
//" }\n"
//" ftc = tc;\n"
//"}\n";
SHADER_SOURCE(attribute highp vec4 position;
attribute highp vec4 tc;
varying highp vec4 ftc;
uniform highp vec4 scale;
void main(void)
{
gl_Position = position * scale;
ftc = tc;
});
static const char *fsstring =
/* "#version 440 core\n"
"#define BINDGROUP(GROUP,INDEX) layout(binding = ((INDEX) | ((GROUP) << 4)))\n"
"BINDGROUP(0, 3) uniform sampler2D tex;\n"
"BINDGROUP(0, 2) uniform Block {\n"
" vec4 scale;\n"
"};\n"
"layout(location = 0) out vec4 color;\n"
"in vec4 ftc;\n"
"void main() {\n"
" color = texture(tex, ftc.xy);\n"
" if (scale.z != 1.0 + 1.0/65536.0) {\n"
" color = vec4(0,0,0,0);\n"
" }\n"
"}\n";*/
SHADER_SOURCE(
varying highp vec4 ftc;
uniform sampler2D tex;
void main (void)
{
gl_FragColor = texture2D(tex, ftc.xy);\n
});
// Two triangles that intersect
static RADfloat vertexData[] = {-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, 0.3f,
0.5f, 0.5f, 0.9f};
// Simple 0/1 texcoords in rgba8 format (used to be color data)
static RADubyte texcoordData[] = {0, 0, 0xFF, 0xFF,
0xFF, 0, 0, 0xFF,
0, 0xFF, 0, 0xFF,
0, 0, 0xFF, 0xFF,
0xFF, 0, 0, 0xFF,
0, 0xFF, 0, 0xFF};
int windowWidth = 500, windowHeight = 500;
int offscreenWidth = 500, offscreenHeight = 500;
typedef enum {
QUEUE,
TOKEN,
COMMAND,
} DrawMode;
DrawMode drawMode = QUEUE /* COMMAND */;
bool benchmark = false;
void InitRAD()
{
PFNRADGETPROCADDRESSPROC getProc = (PFNRADGETPROCADDRESSPROC)eglGetProcAddress("radGetProcAddress");
radLoadProcs(getProc);
// Create the "global" device and one queue
device = radCreateDevice();
queue = radCreateQueue(device, RAD_QUEUE_TYPE_GRAPHICS_AND_COMPUTE);
if (useCopyQueue) {
copyQueue = radCreateQueue(device, RAD_QUEUE_TYPE_GRAPHICS_AND_COMPUTE);
}
}
void CleanRAD()
{
if (useCopyQueue) {
radReleaseQueue(copyQueue);
}
radReleaseQueue(queue);
radReleaseDevice(device);
}
#define USE_MULTISAMPLE 0
RADbuffer AllocAndFillBuffer(RADdevice device, void *data, int sizeofdata, RADbitfield access, bool useCopy)
{
if (useCopy) {
RADbuffer tempbo = radCreateBuffer(device);
radBufferAccess(tempbo, RAD_COPY_READ_ACCESS_BIT);
radBufferMapAccess(tempbo, RAD_MAP_WRITE_BIT | RAD_MAP_PERSISTENT_BIT);
radBufferStorage(tempbo, sizeofdata);
void *ptr = radMapBuffer(tempbo);
memcpy(ptr, data, sizeofdata);
RADbuffer buffer = radCreateBuffer(device);
radBufferAccess(buffer, access | RAD_COPY_WRITE_ACCESS_BIT);
radBufferMapAccess(buffer, 0);
radBufferStorage(buffer, sizeofdata);
radQueueCopyBuffer(useCopyQueue ? copyQueue : queue, tempbo, 0, buffer, 0, sizeofdata);
radReleaseBuffer(tempbo, RAD_TAG_AUTO);
return buffer;
} else {
RADbuffer buffer = radCreateBuffer(device);
radBufferAccess(buffer, access);
radBufferMapAccess(buffer, RAD_MAP_WRITE_BIT | RAD_MAP_PERSISTENT_BIT);
radBufferStorage(buffer, sizeofdata);
void *ptr = radMapBuffer(buffer);
memcpy(ptr, data, sizeofdata);
return buffer;
}
}
void TestRAD()
{
// Create programs from the device, provide them shader code and compile/link them
RADprogram pgm = radCreateProgram(device);
// XXX This is a hack because we don't have an IL. I'm just jamming through the strings
// as if they were an IL blob
const char *source[2] = {vsstring, fsstring};
radProgramSource(pgm, RAD_PROGRAM_FORMAT_GLSL, /*size*/2, (void *)source);
// Create new state vectors
RADcolorState color = radCreateColorState(device);
RADdepthStencilState depth = radCreateDepthStencilState(device);
RADvertexState vertex = radCreateVertexState(device);
RADrasterState raster = radCreateRasterState(device);
RADrtFormatState rtFormat = radCreateRtFormatState(device);
radRtFormatColorFormat(rtFormat, 0, RAD_RGBA8);
radRtFormatDepthFormat(rtFormat, RAD_DEPTH24_STENCIL8);
radDepthStencilDepthTestEnable(depth, RAD_TRUE);
radDepthStencilDepthWriteEnable(depth, RAD_TRUE);
radDepthStencilDepthFunc(depth, RAD_DEPTH_FUNC_LESS);
// Commented out experiments to test different state settings.
//radRasterDiscardEnable(raster, RAD_TRUE);
//radRasterPolygonMode(raster, RAD_POLYGON_MODE_LINE);
//radRasterLineWidth(raster, 10.0f);
//radColorBlendEnable(color, /*MRT index*/0, RAD_TRUE);
//radColorBlendFunc(color, /*MRT index*/0, RAD_BLEND_FUNC_ONE, RAD_BLEND_FUNC_ONE, RAD_BLEND_FUNC_ONE, RAD_BLEND_FUNC_ONE);
//radColorMask(color, /*MRT index*/0, RAD_TRUE, RAD_TRUE, RAD_TRUE, RAD_TRUE);
//radColorLogicOpEnable(color, RAD_TRUE);
//radColorLogicOp(color, RAD_LOGIC_OP_XOR);
// Set the state vector to use two vertex attributes.
//
// Interleaved pos+color
// position = attrib 0 = 3*float at relativeoffset 0
// texcoord = attrib 1 = rgba8 at relativeoffset 0
radVertexAttribFormat(vertex, 0, 3, sizeof(RADfloat), RAD_ATTRIB_TYPE_FLOAT, 0);
radVertexAttribFormat(vertex, 1, 4, sizeof(RADubyte), RAD_ATTRIB_TYPE_UNORM, 0);
radVertexAttribBinding(vertex, 0, 0);
radVertexAttribBinding(vertex, 1, 1);
radVertexBindingGroup(vertex, 0, /*group*/0, /*index*/0);
radVertexBindingGroup(vertex, 1, /*group*/0, /*index*/1);
radVertexAttribEnable(vertex, 0, RAD_TRUE);
radVertexAttribEnable(vertex, 1, RAD_TRUE);
radVertexBindingStride(vertex, 0, 12);
radVertexBindingStride(vertex, 1, 4);
// Create a pipeline.
RADpipeline pipeline = radCreatePipeline(device, RAD_PIPELINE_TYPE_GRAPHICS);
// Attach program and state objects to the pipeline.
radPipelineProgramStages(pipeline, RAD_VERTEX_SHADER_BIT | RAD_FRAGMENT_SHADER_BIT, pgm);
radPipelineColorState(pipeline, color);
radPipelineDepthStencilState(pipeline, depth);
radPipelineVertexState(pipeline, vertex);
radPipelineRasterState(pipeline, raster);
radPipelineRtFormatState(pipeline, rtFormat);
radPipelinePrimitiveType(pipeline, RAD_TRIANGLES);
// Create a vertex buffer and fill it with data
RADbuffer vbo = radCreateBuffer(device);
radBufferAccess(vbo, RAD_VERTEX_ACCESS_BIT);
radBufferMapAccess(vbo, RAD_MAP_WRITE_BIT | RAD_MAP_PERSISTENT_BIT);
radBufferStorage(vbo, sizeof(vertexData)+sizeof(texcoordData));
// create persistent mapping
void *ptr = radMapBuffer(vbo);
// fill ptr with vertex data followed by color data
memcpy(ptr, vertexData, sizeof(vertexData));
memcpy((char *)ptr + sizeof(vertexData), texcoordData, sizeof(texcoordData));
// Get a handle to be used for setting the buffer as a vertex buffer
RADvertexHandle vboHandle = radGetVertexHandle(vbo);
// Create an index buffer and fill it with data
unsigned short indexData[6] = {0, 1, 2, 3, 4, 5};
RADbuffer ibo = AllocAndFillBuffer(device, indexData, sizeof(indexData), RAD_INDEX_ACCESS_BIT, false /*true*/);
// Get a handle to be used for setting the buffer as an index buffer
RADvertexHandle iboHandle = radGetVertexHandle(ibo);
float scale = 1.5f;
if (benchmark) {
scale = 0.2f;
}
float uboData[4] = {scale, scale, 1.0f + 1.0f/65536.0, 1.0f};
RADbuffer ubo = AllocAndFillBuffer(device, uboData, sizeof(uboData), RAD_UNIFORM_ACCESS_BIT, false);
// Get a handle to be used for setting the buffer as a uniform buffer
RADuniformHandle uboHandle = radGetUniformHandle(ubo);
#if USE_MULTISAMPLE
RADtexture rtTex = radCreateTexture(device);
radTextureAccess(rtTex, RAD_RENDER_TARGET_ACCESS_BIT);
radTextureStorage(rtTex, RAD_TEXTURE_2D_MULTISAMPLE, 1, RAD_RGBA8, offscreenWidth, offscreenHeight, 1, 4);
RADtexture depthTex = radCreateTexture(device);
radTextureAccess(depthTex, RAD_RENDER_TARGET_ACCESS_BIT);
radTextureStorage(depthTex, RAD_TEXTURE_2D_MULTISAMPLE, 1, RAD_DEPTH24_STENCIL8, offscreenWidth, offscreenHeight, 1, 4);
RADtexture tex1x = radCreateTexture(device);
radTextureAccess(tex1x, RAD_RENDER_TARGET_ACCESS_BIT);
radTextureStorage(tex1x, RAD_TEXTURE_2D, 1, RAD_RGBA8, offscreenWidth, offscreenHeight, 1, 0);
// Create and bind a rendertarget handle
RADrenderTargetHandle rtHandle = radGetTextureRenderTargetHandle(rtTex, RAD_TEXTURE_2D, RAD_RGBA8, 0, 0, 1);
RADrenderTargetHandle depthHandle = radGetTextureRenderTargetHandle(depthTex, RAD_TEXTURE_2D, RAD_DEPTH24_STENCIL8, 0, 0, 1);
radRasterSamples(raster, 4);
radRtFormatColorSamples(rtFormat, 4);
radRtFormatDepthStencilSamples(rtFormat, 4);
RADpass pass = radCreatePass(device);
radPassRenderTargets(pass, 1, &rtHandle, depthHandle, 0);
radPassResolve(pass, RAD_RT_ATTACHMENT_COLOR0, tex1x);
#else
RADtexture rtTex = radCreateTexture(device);
radTextureAccess(rtTex, RAD_RENDER_TARGET_ACCESS_BIT);
radTextureStorage(rtTex, RAD_TEXTURE_2D, 1, RAD_RGBA8, offscreenWidth, offscreenHeight, 1, 0);
RADtexture depthTex = radCreateTexture(device);
radTextureAccess(depthTex, RAD_RENDER_TARGET_ACCESS_BIT);
radTextureStorage(depthTex, RAD_TEXTURE_2D, 1, RAD_DEPTH24_STENCIL8, offscreenWidth, offscreenHeight, 1, 0);
// Create and bind a rendertarget handle
RADrenderTargetHandle rtHandle = radGetTextureRenderTargetHandle(rtTex, RAD_TEXTURE_2D, RAD_RGBA8, 0, 0, 1);
RADrenderTargetHandle depthHandle = radGetTextureRenderTargetHandle(depthTex, RAD_TEXTURE_2D, RAD_DEPTH24_STENCIL8, 0, 0, 1);
RADpass pass = radCreatePass(device);
radPassRenderTargets(pass, 1, &rtHandle, depthHandle, 0);
#endif
radCompilePass(pass);
radCompilePipeline(pipeline);
RADpipelineHandle pipelineHandle = radGetPipelineHandle(pipeline);
RADsampler sampler = radCreateSampler(device);
// Commented out experiments to test different state settings.
//radSamplerMinMagFilter(sampler, RAD_MIN_FILTER_NEAREST, RAD_MAG_FILTER_NEAREST);
const int texWidth = 4, texHeight = 4;
RADtexture texture = radCreateTexture(device);
radTextureAccess(texture, RAD_TEXTURE_ACCESS_BIT);
radTextureStorage(texture, RAD_TEXTURE_2D, 1, RAD_RGBA8, texWidth, texHeight, 1, 0);
RADtextureHandle texHandle = radGetTextureSamplerHandle(texture, sampler, RAD_TEXTURE_2D, RAD_RGBA8,
/*minLevel*/0, /*numLevels*/1, /*minLayer*/0, /*numLayers*/1);
RADbuffer pbo = radCreateBuffer(device);
radBufferAccess(pbo, RAD_COPY_READ_ACCESS_BIT);
radBufferMapAccess(pbo, RAD_MAP_WRITE_BIT | RAD_MAP_PERSISTENT_BIT);
radBufferStorage(pbo, texWidth*texHeight*4);
unsigned char *texdata = (unsigned char *)radMapBuffer(pbo);
// fill with texture data
for (int j = 0; j < texWidth; ++j) {
for (int i = 0; i < texHeight; ++i) {
texdata[4*(j*texWidth+i)+0] = 0xFF*((i+j)&1);
texdata[4*(j*texWidth+i)+1] = 0x00*((i+j)&1);
texdata[4*(j*texWidth+i)+2] = ~(0xFF*((i+j)&1));
texdata[4*(j*texWidth+i)+3] = 0xFF;
}
}
// XXX missing pixelpack object
// Download the texture data
radQueueCopyBufferToImage(queue, pbo, 0, texture, 0, 0, 0, 0, texWidth, texHeight, 1);
radQueueBeginPass(queue, pass);
// Some scissored clears
{
radQueueScissor(queue, 0, 0, offscreenWidth, offscreenHeight);
float clearColor[4] = {0, 0, 0, 1};
radQueueClearColor(queue, 0, clearColor);
radQueueClearDepth(queue, 1.0f);
}
{
radQueueScissor(queue, 0, 0, offscreenWidth/2, offscreenHeight/2);
float clearColor[4] = {0, 1, 0, 1};
radQueueClearColor(queue, 0, clearColor);
}
{
radQueueScissor(queue, offscreenWidth/2, offscreenHeight/2, offscreenWidth/2, offscreenHeight/2);
float clearColor[4] = {0, 0, 1, 1};
radQueueClearColor(queue, 0, clearColor);
}
radQueueScissor(queue, 0, 0, offscreenWidth, offscreenHeight);
radQueueViewport(queue, 0, 0, offscreenWidth, offscreenHeight);
RADbindGroupElement b[4] = {{vboHandle, 0, 0}, {vboHandle, sizeof(vertexData), 0}, {uboHandle, 0, 4*sizeof(float)}, {texHandle, 0, 0}};
RADbuffer bindGroup = AllocAndFillBuffer(device, b, sizeof(b), RAD_BINDGROUP_ACCESS_BIT, false);
RADbindGroupHandle bindGroupHandle = radGetBindGroupHandle(bindGroup);
if (useCopyQueue) {
// Sync from copy queue to graphics queue. Note that we currently don't sync in the
// opposite direction at the end of the frame, because radQueuePresent effectively
// does a Finish so it isn't needed.
RADsync sync = radCreateSync(device);
radQueueFenceSync(copyQueue, sync, RAD_SYNC_ALL_GPU_COMMANDS_COMPLETE, 0);
radQueueWaitSync(queue, sync);
radReleaseSync(sync);
}
clock_t startTime = clock();
unsigned int numIterations = benchmark ? 1000000 : 1;
switch (drawMode) {
case QUEUE:
for (unsigned int i = 0; i < numIterations; ++i) {
// Bind the pipeline, bind vertex arrays and textures, and draw
radQueueBindPipeline(queue, RAD_PIPELINE_TYPE_GRAPHICS, pipelineHandle);
radQueueBindGroup(queue, RAD_VERTEX_SHADER_BIT | RAD_FRAGMENT_SHADER_BIT, 0, 4, bindGroupHandle, 0);
//radQueueDrawArrays(queue, RAD_TRIANGLES, 0, 6);
radQueueDrawElements(queue, RAD_TRIANGLES, RAD_INDEX_UNSIGNED_SHORT, 6, iboHandle, 0);
}
break;
case TOKEN:
{
typedef struct Draw {
RADuint pipelineHeader;
RADtokenBindGraphicsPipeline pipeline;
RADuint bindGroupHeader;
RADtokenBindGroup bindGroup;
RADuint drawElementsHeader;
RADtokenDrawElements drawElements;
} Draw;
Draw d;
memset(&d, 0, sizeof(d));
d.pipelineHeader = radGetTokenHeader(device, RAD_TOKEN_BIND_GRAPHICS_PIPELINE);
d.pipeline.pipelineHandle = pipelineHandle;
d.bindGroupHeader = radGetTokenHeader(device, RAD_TOKEN_BIND_GROUP);
d.bindGroup.stages = RAD_VERTEX_SHADER_BIT | RAD_FRAGMENT_SHADER_BIT;
d.bindGroup.group = 0;
d.bindGroup.groupHandle = bindGroupHandle;
d.bindGroup.offset = 0;
d.bindGroup.count = 4;
d.drawElementsHeader = radGetTokenHeader(device, RAD_TOKEN_DRAW_ELEMENTS);
d.drawElements.indexHandle = iboHandle;
d.drawElements.mode = RAD_TRIANGLES;
d.drawElements.type = RAD_INDEX_UNSIGNED_SHORT;
d.drawElements.count = 6;
for (unsigned int i = 0; i < numIterations; ++i) {
radQueueSubmitDynamic(queue, &d, sizeof(d));
}
}
break;
case COMMAND:
{
RADcommandBuffer cmd = radCreateCommandBuffer(device, RAD_QUEUE_TYPE_GRAPHICS_AND_COMPUTE);
radCmdBindPipeline(cmd, RAD_PIPELINE_TYPE_GRAPHICS, pipelineHandle);
radCmdBindGroup(cmd, RAD_VERTEX_SHADER_BIT | RAD_FRAGMENT_SHADER_BIT, 0, 4, bindGroupHandle, 0);
radCmdDrawElements(cmd, RAD_TRIANGLES, RAD_INDEX_UNSIGNED_SHORT, 6, iboHandle, 0);
radCompileCommandBuffer(cmd);
RADcommandHandle cmdHandle = radGetCommandHandle(cmd);
for (unsigned int i = 0; i < numIterations; ++i) {
radQueueSubmitCommands(queue, 1, &cmdHandle);
}
radReleaseCommandBuffer(cmd);
}
break;
}
if (benchmark) {
clock_t currentTime = clock();
printf("%f\n", 1.0f*numIterations*CLOCKS_PER_SEC/(currentTime - startTime));
}
radQueueEndPass(queue, pass);
// Kickoff submitted command buffers for the queue
//radFlushQueue(queue);
#if USE_MULTISAMPLE
radQueuePresent(queue, tex1x);
#else
radQueuePresent(queue, rtTex);
#endif
radReleaseProgram(pgm);
radReleaseColorState(color);
radReleaseDepthStencilState(depth);
radReleaseVertexState(vertex);
radReleaseRasterState(raster);
radReleaseRtFormatState(rtFormat);
radReleaseBuffer(vbo, RAD_TAG_AUTO);
radReleaseBuffer(ibo, RAD_TAG_AUTO);
radReleaseBuffer(pbo, RAD_TAG_AUTO);
radReleaseBuffer(ubo, RAD_TAG_AUTO);
radReleaseBuffer(bindGroup, RAD_TAG_AUTO);
radReleaseTexture(texture, RAD_TAG_AUTO);
radReleaseTexture(rtTex, RAD_TAG_AUTO);
radReleaseTexture(depthTex, RAD_TAG_AUTO);
radReleaseSampler(sampler);
radReleasePipeline(pipeline);
radReleasePass(pass);
#if USE_MULTISAMPLE
radReleaseTexture(tex1x, RAD_TAG_AUTO);
#endif
}