diff options
Diffstat (limited to 'tools/gpu/gl/null/NullGLTestContext.cpp')
-rw-r--r-- | tools/gpu/gl/null/NullGLTestContext.cpp | 630 |
1 files changed, 630 insertions, 0 deletions
diff --git a/tools/gpu/gl/null/NullGLTestContext.cpp b/tools/gpu/gl/null/NullGLTestContext.cpp new file mode 100644 index 0000000000..44abf59370 --- /dev/null +++ b/tools/gpu/gl/null/NullGLTestContext.cpp @@ -0,0 +1,630 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "NullGLTestContext.h" +#include "gl/GrGLTestInterface.h" +#include "gl/GrGLDefines.h" +#include "gl/GrGLInterface.h" +#include "gl/GrGLTypes.h" +#include "SkMutex.h" +#include "SkTDArray.h" + +namespace { + +class BufferObj { +public: + BufferObj(GrGLuint id) : fID(id), fDataPtr(nullptr), fSize(0), fMapped(false) {} + ~BufferObj() { delete[] fDataPtr; } + + void allocate(GrGLsizeiptr size, const GrGLchar* dataPtr) { + if (fDataPtr) { + SkASSERT(0 != fSize); + delete[] fDataPtr; + } + + fSize = size; + fDataPtr = new char[size]; + } + + GrGLuint id() const { return fID; } + GrGLchar* dataPtr() { return fDataPtr; } + GrGLsizeiptr size() const { return fSize; } + + void setMapped(bool mapped) { fMapped = mapped; } + bool mapped() const { return fMapped; } + +private: + GrGLuint fID; + GrGLchar* fDataPtr; + GrGLsizeiptr fSize; // size in bytes + bool fMapped; +}; + +// This class maintains a sparsely populated array of buffer pointers. +class BufferManager { +public: + BufferManager() : fFreeListHead(kFreeListEnd) {} + + ~BufferManager() { + // nullptr out the entries that are really free list links rather than ptrs before deleting. + intptr_t curr = fFreeListHead; + while (kFreeListEnd != curr) { + intptr_t next = reinterpret_cast<intptr_t>(fBuffers[SkToS32(curr)]); + fBuffers[SkToS32(curr)] = nullptr; + curr = next; + } + + fBuffers.deleteAll(); + } + + BufferObj* lookUp(GrGLuint id) { + BufferObj* buffer = fBuffers[id]; + SkASSERT(buffer && buffer->id() == id); + return buffer; + } + + BufferObj* create() { + GrGLuint id; + BufferObj* buffer; + + if (kFreeListEnd == fFreeListHead) { + // no free slots - create a new one + id = fBuffers.count(); + buffer = new BufferObj(id); + *fBuffers.append() = buffer; + } else { + // grab the head of the free list and advance the head to the next free slot. + id = static_cast<GrGLuint>(fFreeListHead); + fFreeListHead = reinterpret_cast<intptr_t>(fBuffers[id]); + + buffer = new BufferObj(id); + fBuffers[id] = buffer; + } + + return buffer; + } + + void free(BufferObj* buffer) { + SkASSERT(fBuffers.count() > 0); + + GrGLuint id = buffer->id(); + delete buffer; + + fBuffers[id] = reinterpret_cast<BufferObj*>(fFreeListHead); + fFreeListHead = id; + } + +private: + static const intptr_t kFreeListEnd = -1; + // Index of the first entry of fBuffers in the free list. Free slots in fBuffers are indices to + // the next free slot. The last free slot has a value of kFreeListEnd. + intptr_t fFreeListHead; + SkTDArray<BufferObj*> fBuffers; +}; + +/** Null interface implementation */ +class NullInterface : public GrGLTestInterface { +public: + NullInterface() + : fCurrArrayBuffer(0) + , fCurrElementArrayBuffer(0) + , fCurrPixelPackBuffer(0) + , fCurrPixelUnpackBuffer(0) + , fCurrShaderID(0) + , fCurrGenericID(0) + , fCurrUniformLocation(0) { + this->init(kGL_GrGLStandard); + } + + GrGLenum checkFramebufferStatus(GrGLenum target) override { + return GR_GL_FRAMEBUFFER_COMPLETE; + } + + GrGLvoid genBuffers(GrGLsizei n, GrGLuint* ids) override { + for (int i = 0; i < n; ++i) { + BufferObj* buffer = fBufferManager.create(); + ids[i] = buffer->id(); + } + } + + GrGLvoid bufferData(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data, + GrGLenum usage) override { + GrGLuint id = 0; + + switch (target) { + case GR_GL_ARRAY_BUFFER: + id = fCurrArrayBuffer; + break; + case GR_GL_ELEMENT_ARRAY_BUFFER: + id = fCurrElementArrayBuffer; + break; + case GR_GL_PIXEL_PACK_BUFFER: + id = fCurrPixelPackBuffer; + break; + case GR_GL_PIXEL_UNPACK_BUFFER: + id = fCurrPixelUnpackBuffer; + break; + default: + SkFAIL("Unexpected target to nullGLBufferData"); + break; + } + + if (id > 0) { + BufferObj* buffer = fBufferManager.lookUp(id); + buffer->allocate(size, (const GrGLchar*) data); + } + } + + GrGLuint createProgram() override { + return ++fCurrProgramID; + } + + GrGLuint createShader(GrGLenum type) override { + return ++fCurrShaderID; + } + + GrGLvoid bindBuffer(GrGLenum target, GrGLuint buffer) override { + switch (target) { + case GR_GL_ARRAY_BUFFER: + fCurrArrayBuffer = buffer; + break; + case GR_GL_ELEMENT_ARRAY_BUFFER: + fCurrElementArrayBuffer = buffer; + break; + case GR_GL_PIXEL_PACK_BUFFER: + fCurrPixelPackBuffer = buffer; + break; + case GR_GL_PIXEL_UNPACK_BUFFER: + fCurrPixelUnpackBuffer = buffer; + break; + } + } + + // deleting a bound buffer has the side effect of binding 0 + GrGLvoid deleteBuffers(GrGLsizei n, const GrGLuint* ids) override { + for (int i = 0; i < n; ++i) { + if (ids[i] == fCurrArrayBuffer) { + fCurrArrayBuffer = 0; + } + if (ids[i] == fCurrElementArrayBuffer) { + fCurrElementArrayBuffer = 0; + } + if (ids[i] == fCurrPixelPackBuffer) { + fCurrPixelPackBuffer = 0; + } + if (ids[i] == fCurrPixelUnpackBuffer) { + fCurrPixelUnpackBuffer = 0; + } + + BufferObj* buffer = fBufferManager.lookUp(ids[i]); + fBufferManager.free(buffer); + } + } + + GrGLvoid genFramebuffers(GrGLsizei n, GrGLuint *framebuffers) override { + this->genGenericIds(n, framebuffers); + } + + GrGLvoid genQueries(GrGLsizei n, GrGLuint *ids) override { this->genGenericIds(n, ids); } + + GrGLvoid genRenderbuffers(GrGLsizei n, GrGLuint *renderbuffers) override { + this->genGenericIds(n, renderbuffers); + } + + GrGLvoid genTextures(GrGLsizei n, GrGLuint *textures) override { + this->genGenericIds(n, textures); + } + + GrGLvoid genVertexArrays(GrGLsizei n, GrGLuint *arrays) override { + this->genGenericIds(n, arrays); + } + + GrGLenum getError() override { return GR_GL_NO_ERROR; } + + GrGLvoid getIntegerv(GrGLenum pname, GrGLint* params) override { + // TODO: remove from Ganesh the #defines for gets we don't use. + // We would like to minimize gets overall due to performance issues + switch (pname) { + case GR_GL_CONTEXT_PROFILE_MASK: + *params = GR_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT; + break; + case GR_GL_STENCIL_BITS: + *params = 8; + break; + case GR_GL_SAMPLES: + *params = 1; + break; + case GR_GL_FRAMEBUFFER_BINDING: + *params = 0; + break; + case GR_GL_VIEWPORT: + params[0] = 0; + params[1] = 0; + params[2] = 800; + params[3] = 600; + break; + case GR_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: + case GR_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS: + case GR_GL_MAX_TEXTURE_IMAGE_UNITS: + case GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: + *params = 8; + break; + case GR_GL_MAX_TEXTURE_COORDS: + *params = 8; + break; + case GR_GL_MAX_VERTEX_UNIFORM_VECTORS: + *params = kDefaultMaxVertexUniformVectors; + break; + case GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS: + *params = kDefaultMaxFragmentUniformVectors; + break; + case GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: + *params = 16 * 4; + break; + case GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS: + *params = 0; + break; + case GR_GL_COMPRESSED_TEXTURE_FORMATS: + break; + case GR_GL_MAX_TEXTURE_SIZE: + *params = 8192; + break; + case GR_GL_MAX_RENDERBUFFER_SIZE: + *params = 8192; + break; + case GR_GL_MAX_SAMPLES: + *params = 32; + break; + case GR_GL_MAX_VERTEX_ATTRIBS: + *params = kDefaultMaxVertexAttribs; + break; + case GR_GL_MAX_VARYING_VECTORS: + *params = kDefaultMaxVaryingVectors; + break; + case GR_GL_NUM_EXTENSIONS: { + GrGLint i = 0; + while (kExtensions[i++]); + *params = i; + break; + } + default: + SkFAIL("Unexpected pname to GetIntegerv"); + } + } + + GrGLvoid getProgramiv(GrGLuint program, GrGLenum pname, GrGLint* params) override { + this->getShaderOrProgramiv(program, pname, params); + } + + GrGLvoid getProgramInfoLog(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length, + char* infolog) override { + this->getInfoLog(program, bufsize, length, infolog); + } + + GrGLvoid getMultisamplefv(GrGLenum pname, GrGLuint index, GrGLfloat* val) override { + val[0] = val[1] = 0.5f; + } + + GrGLvoid getQueryiv(GrGLenum GLtarget, GrGLenum pname, GrGLint *params) override { + switch (pname) { + case GR_GL_CURRENT_QUERY: + *params = 0; + break; + case GR_GL_QUERY_COUNTER_BITS: + *params = 32; + break; + default: + SkFAIL("Unexpected pname passed GetQueryiv."); + } + } + + GrGLvoid getQueryObjecti64v(GrGLuint id, GrGLenum pname, GrGLint64 *params) override { + this->queryResult(id, pname, params); + } + + GrGLvoid getQueryObjectiv(GrGLuint id, GrGLenum pname, GrGLint *params) override { + this->queryResult(id, pname, params); + } + + GrGLvoid getQueryObjectui64v(GrGLuint id, GrGLenum pname, GrGLuint64 *params) override { + this->queryResult(id, pname, params); + } + + GrGLvoid getQueryObjectuiv(GrGLuint id, GrGLenum pname, GrGLuint *params) override { + this->queryResult(id, pname, params); + } + + GrGLvoid getShaderiv(GrGLuint shader, GrGLenum pname, GrGLint* params) override { + this->getShaderOrProgramiv(shader, pname, params); + } + + GrGLvoid getShaderInfoLog(GrGLuint shader, GrGLsizei bufsize, GrGLsizei* length, + char* infolog) override { + this->getInfoLog(shader, bufsize, length, infolog); + } + + const GrGLubyte* getString(GrGLenum name) override { + switch (name) { + case GR_GL_EXTENSIONS: + return CombinedExtensionString(); + case GR_GL_VERSION: + return (const GrGLubyte*)"4.0 Null GL"; + case GR_GL_SHADING_LANGUAGE_VERSION: + return (const GrGLubyte*)"4.20.8 Null GLSL"; + case GR_GL_VENDOR: + return (const GrGLubyte*)"Null Vendor"; + case GR_GL_RENDERER: + return (const GrGLubyte*)"The Null (Non-)Renderer"; + default: + SkFAIL("Unexpected name passed to GetString"); + return nullptr; + } + } + + const GrGLubyte* getStringi(GrGLenum name, GrGLuint i) override { + switch (name) { + case GR_GL_EXTENSIONS: { + GrGLint count; + this->getIntegerv(GR_GL_NUM_EXTENSIONS, &count); + if ((GrGLint)i <= count) { + return (const GrGLubyte*) kExtensions[i]; + } else { + return nullptr; + } + } + default: + SkFAIL("Unexpected name passed to GetStringi"); + return nullptr; + } + } + + GrGLint getUniformLocation(GrGLuint program, const char* name) override { + return ++fCurrUniformLocation; + } + + GrGLvoid* mapBufferRange(GrGLenum target, GrGLintptr offset, GrGLsizeiptr length, + GrGLbitfield access) override { + GrGLuint id = 0; + switch (target) { + case GR_GL_ARRAY_BUFFER: + id = fCurrArrayBuffer; + break; + case GR_GL_ELEMENT_ARRAY_BUFFER: + id = fCurrElementArrayBuffer; + break; + case GR_GL_PIXEL_PACK_BUFFER: + id = fCurrPixelPackBuffer; + break; + case GR_GL_PIXEL_UNPACK_BUFFER: + id = fCurrPixelUnpackBuffer; + break; + } + + if (id > 0) { + // We just ignore the offset and length here. + BufferObj* buffer = fBufferManager.lookUp(id); + SkASSERT(!buffer->mapped()); + buffer->setMapped(true); + return buffer->dataPtr(); + } + return nullptr; + } + + GrGLvoid* mapBuffer(GrGLenum target, GrGLenum access) override { + GrGLuint id = 0; + switch (target) { + case GR_GL_ARRAY_BUFFER: + id = fCurrArrayBuffer; + break; + case GR_GL_ELEMENT_ARRAY_BUFFER: + id = fCurrElementArrayBuffer; + break; + case GR_GL_PIXEL_PACK_BUFFER: + id = fCurrPixelPackBuffer; + break; + case GR_GL_PIXEL_UNPACK_BUFFER: + id = fCurrPixelUnpackBuffer; + break; + } + + if (id > 0) { + BufferObj* buffer = fBufferManager.lookUp(id); + SkASSERT(!buffer->mapped()); + buffer->setMapped(true); + return buffer->dataPtr(); + } + + SkASSERT(false); + return nullptr; // no buffer bound to target + } + + GrGLboolean unmapBuffer(GrGLenum target) override { + GrGLuint id = 0; + switch (target) { + case GR_GL_ARRAY_BUFFER: + id = fCurrArrayBuffer; + break; + case GR_GL_ELEMENT_ARRAY_BUFFER: + id = fCurrElementArrayBuffer; + break; + case GR_GL_PIXEL_PACK_BUFFER: + id = fCurrPixelPackBuffer; + break; + case GR_GL_PIXEL_UNPACK_BUFFER: + id = fCurrPixelUnpackBuffer; + break; + } + if (id > 0) { + BufferObj* buffer = fBufferManager.lookUp(id); + SkASSERT(buffer->mapped()); + buffer->setMapped(false); + return GR_GL_TRUE; + } + + GrAlwaysAssert(false); + return GR_GL_FALSE; // GR_GL_INVALID_OPERATION; + } + + GrGLvoid getBufferParameteriv(GrGLenum target, GrGLenum pname, GrGLint* params) override { + switch (pname) { + case GR_GL_BUFFER_MAPPED: { + *params = GR_GL_FALSE; + GrGLuint id = 0; + switch (target) { + case GR_GL_ARRAY_BUFFER: + id = fCurrArrayBuffer; + break; + case GR_GL_ELEMENT_ARRAY_BUFFER: + id = fCurrElementArrayBuffer; + break; + case GR_GL_PIXEL_PACK_BUFFER: + id = fCurrPixelPackBuffer; + break; + case GR_GL_PIXEL_UNPACK_BUFFER: + id = fCurrPixelUnpackBuffer; + break; + } + if (id > 0) { + BufferObj* buffer = fBufferManager.lookUp(id); + if (buffer->mapped()) { + *params = GR_GL_TRUE; + } + } + break; } + default: + SkFAIL("Unexpected pname to GetBufferParamateriv"); + break; + } + }; + +private: + BufferManager fBufferManager; + GrGLuint fCurrArrayBuffer; + GrGLuint fCurrElementArrayBuffer; + GrGLuint fCurrPixelPackBuffer; + GrGLuint fCurrPixelUnpackBuffer; + GrGLuint fCurrProgramID; + GrGLuint fCurrShaderID; + GrGLuint fCurrGenericID; + GrGLuint fCurrUniformLocation; + + // the OpenGLES 2.0 spec says this must be >= 128 + static const GrGLint kDefaultMaxVertexUniformVectors = 128; + + // the OpenGLES 2.0 spec says this must be >=16 + static const GrGLint kDefaultMaxFragmentUniformVectors = 16; + + // the OpenGLES 2.0 spec says this must be >= 8 + static const GrGLint kDefaultMaxVertexAttribs = 8; + + // the OpenGLES 2.0 spec says this must be >= 8 + static const GrGLint kDefaultMaxVaryingVectors = 8; + + static const char* kExtensions[]; + + static const GrGLubyte* CombinedExtensionString() { + static SkString gExtString; + static SkMutex gMutex; + gMutex.acquire(); + if (0 == gExtString.size()) { + int i = 0; + while (kExtensions[i]) { + if (i > 0) { + gExtString.append(" "); + } + gExtString.append(kExtensions[i]); + ++i; + } + } + gMutex.release(); + return (const GrGLubyte*) gExtString.c_str(); + } + + GrGLvoid genGenericIds(GrGLsizei n, GrGLuint* ids) { + for (int i = 0; i < n; ++i) { + ids[i] = ++fCurrGenericID; + } + } + + GrGLvoid getInfoLog(GrGLuint object, GrGLsizei bufsize, GrGLsizei* length, + char* infolog) { + if (length) { + *length = 0; + } + if (bufsize > 0) { + *infolog = 0; + } + } + + GrGLvoid getShaderOrProgramiv(GrGLuint object, GrGLenum pname, GrGLint* params) { + switch (pname) { + case GR_GL_LINK_STATUS: // fallthru + case GR_GL_COMPILE_STATUS: + *params = GR_GL_TRUE; + break; + case GR_GL_INFO_LOG_LENGTH: + *params = 0; + break; + // we don't expect any other pnames + default: + SkFAIL("Unexpected pname to GetProgramiv"); + break; + } + } + + template <typename T> + void queryResult(GrGLenum GLtarget, GrGLenum pname, T *params) { + switch (pname) { + case GR_GL_QUERY_RESULT_AVAILABLE: + *params = GR_GL_TRUE; + break; + case GR_GL_QUERY_RESULT: + *params = 0; + break; + default: + SkFAIL("Unexpected pname passed to GetQueryObject."); + break; + } + } + + typedef GrGLTestInterface INHERITED; +}; + +const char* NullInterface::kExtensions[] = { + "GL_ARB_framebuffer_object", + "GL_ARB_blend_func_extended", + "GL_ARB_timer_query", + "GL_ARB_draw_buffers", + "GL_ARB_occlusion_query", + "GL_EXT_stencil_wrap", + nullptr, // signifies the end of the array. +}; + +class NullGLContext : public sk_gpu_test::GLTestContext { +public: + NullGLContext() { this->init(new NullInterface); } + ~NullGLContext() override { this->teardown(); } + +private: + void onPlatformMakeCurrent() const override {}; + void onPlatformSwapBuffers() const override {} + GrGLFuncPtr onPlatformGetProcAddress(const char*) const override { return nullptr; } +}; +} // anonymous namespace + +namespace sk_gpu_test { +GLTestContext* CreateNullGLTestContext() { + GLTestContext* ctx = new NullGLContext(); + if (ctx->isValid()) { + return ctx; + } + delete ctx; + return nullptr; +} +} // namespace sk_gpu_test + |