зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1130616 - Support EXT_color_buffer_half_float on ANGLE. - r=jrmuizel,khuey
This commit is contained in:
Родитель
ad69b19ecc
Коммит
75d555e953
|
@ -1852,6 +1852,12 @@ WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget,
|
|||
return ok;
|
||||
}
|
||||
|
||||
size_t mozilla::RoundUpToMultipleOf(size_t value, size_t multiple)
|
||||
{
|
||||
size_t overshoot = value + multiple - 1;
|
||||
return overshoot - (overshoot % multiple);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl)
|
||||
|
@ -1875,6 +1881,7 @@ WebGLContext::ScopedMaskWorkaround::~ScopedMaskWorkaround()
|
|||
mWebGL.mColorWriteMask[3]);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// XPCOM goop
|
||||
|
||||
|
|
|
@ -1092,9 +1092,7 @@ protected:
|
|||
GLenum pname);
|
||||
|
||||
// Returns x rounded to the next highest multiple of y.
|
||||
static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x,
|
||||
CheckedUint32 y)
|
||||
{
|
||||
static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y) {
|
||||
return ((x + y - 1) / y) * y;
|
||||
}
|
||||
|
||||
|
@ -1693,6 +1691,8 @@ private:
|
|||
WebGLContext* mWebGL;
|
||||
};
|
||||
|
||||
size_t RoundUpToMultipleOf(size_t value, size_t multiple);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,8 +49,8 @@ WebGLContext::Clear(GLbitfield mask)
|
|||
mShouldPresent = true;
|
||||
}
|
||||
|
||||
static GLclampf
|
||||
GLClampFloat(GLclampf val)
|
||||
static GLfloat
|
||||
GLClampFloat(GLfloat val)
|
||||
{
|
||||
if (val < 0.0)
|
||||
return 0.0;
|
||||
|
@ -62,18 +62,28 @@ GLClampFloat(GLclampf val)
|
|||
}
|
||||
|
||||
void
|
||||
WebGLContext::ClearColor(GLclampf r, GLclampf g,
|
||||
GLclampf b, GLclampf a)
|
||||
WebGLContext::ClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
mColorClearValue[0] = GLClampFloat(r);
|
||||
mColorClearValue[1] = GLClampFloat(g);
|
||||
mColorClearValue[2] = GLClampFloat(b);
|
||||
mColorClearValue[3] = GLClampFloat(a);
|
||||
|
||||
const bool supportsFloatColorBuffers = (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) ||
|
||||
IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float));
|
||||
if (!supportsFloatColorBuffers) {
|
||||
r = GLClampFloat(r);
|
||||
g = GLClampFloat(g);
|
||||
b = GLClampFloat(b);
|
||||
a = GLClampFloat(a);
|
||||
}
|
||||
|
||||
gl->fClearColor(r, g, b, a);
|
||||
|
||||
mColorClearValue[0] = r;
|
||||
mColorClearValue[1] = g;
|
||||
mColorClearValue[2] = b;
|
||||
mColorClearValue[3] = a;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1863,6 +1863,84 @@ SetFullAlpha(void* data, GLenum format, GLenum type, size_t width,
|
|||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
ReadPixelsAndConvert(gl::GLContext* gl, GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum readFormat, GLenum readType, size_t pixelStorePackAlignment,
|
||||
GLenum destFormat, GLenum destType, void* destBytes)
|
||||
{
|
||||
if (readFormat == destFormat && readType == destType) {
|
||||
gl->fReadPixels(x, y, width, height, destFormat, destType, destBytes);
|
||||
return;
|
||||
}
|
||||
|
||||
if (readFormat == LOCAL_GL_RGBA &&
|
||||
readType == LOCAL_GL_HALF_FLOAT &&
|
||||
destFormat == LOCAL_GL_RGBA &&
|
||||
destType == LOCAL_GL_FLOAT)
|
||||
{
|
||||
size_t readBytesPerPixel = sizeof(uint16_t) * 4;
|
||||
size_t destBytesPerPixel = sizeof(float) * 4;
|
||||
|
||||
size_t readBytesPerRow = readBytesPerPixel * width;
|
||||
|
||||
size_t readStride = RoundUpToMultipleOf(readBytesPerRow, pixelStorePackAlignment);
|
||||
size_t destStride = RoundUpToMultipleOf(destBytesPerPixel * width,
|
||||
pixelStorePackAlignment);
|
||||
|
||||
size_t bytesNeeded = ((height - 1) * readStride) + readBytesPerRow;
|
||||
UniquePtr<uint8_t[]> readBuffer(new uint8_t[bytesNeeded]);
|
||||
|
||||
gl->fReadPixels(x, y, width, height, readFormat, readType, readBuffer.get());
|
||||
|
||||
size_t channelsPerRow = width * 4;
|
||||
for (size_t j = 0; j < (size_t)height; j++) {
|
||||
uint16_t* src = (uint16_t*)(readBuffer.get()) + j*readStride;
|
||||
float* dst = (float*)(destBytes) + j*destStride;
|
||||
|
||||
uint16_t* srcEnd = src + channelsPerRow;
|
||||
while (src != srcEnd) {
|
||||
*dst = unpackFromFloat16(*src);
|
||||
|
||||
++src;
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_CRASH("bad format/type");
|
||||
}
|
||||
|
||||
static bool
|
||||
IsFormatAndTypeUnpackable(GLenum format, GLenum type)
|
||||
{
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
case LOCAL_GL_FLOAT:
|
||||
case LOCAL_GL_HALF_FLOAT:
|
||||
case LOCAL_GL_HALF_FLOAT_OES:
|
||||
switch (format) {
|
||||
case LOCAL_GL_ALPHA:
|
||||
case LOCAL_GL_RGB:
|
||||
case LOCAL_GL_RGBA:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
return format == LOCAL_GL_RGBA;
|
||||
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
||||
return format == LOCAL_GL_RGB;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
GLsizei height, GLenum format,
|
||||
|
@ -1883,59 +1961,61 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
if (pixels.IsNull())
|
||||
return ErrorInvalidValue("readPixels: null destination buffer");
|
||||
|
||||
if (!IsFormatAndTypeUnpackable(format, type))
|
||||
return ErrorInvalidEnum("readPixels: Bad format or type.");
|
||||
|
||||
const WebGLRectangleObject* framebufferRect = CurValidReadFBRectObject();
|
||||
GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
|
||||
GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
|
||||
|
||||
uint32_t channels = 0;
|
||||
int channels = 0;
|
||||
|
||||
// Check the format param
|
||||
switch (format) {
|
||||
case LOCAL_GL_ALPHA:
|
||||
channels = 1;
|
||||
break;
|
||||
case LOCAL_GL_RGB:
|
||||
channels = 3;
|
||||
break;
|
||||
case LOCAL_GL_RGBA:
|
||||
channels = 4;
|
||||
break;
|
||||
default:
|
||||
return ErrorInvalidEnum("readPixels: Bad format");
|
||||
case LOCAL_GL_ALPHA:
|
||||
channels = 1;
|
||||
break;
|
||||
case LOCAL_GL_RGB:
|
||||
channels = 3;
|
||||
break;
|
||||
case LOCAL_GL_RGBA:
|
||||
channels = 4;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("bad `format`");
|
||||
}
|
||||
|
||||
uint32_t bytesPerPixel = 0;
|
||||
int requiredDataType = 0;
|
||||
|
||||
// Check the type param
|
||||
bool isReadTypeValid = false;
|
||||
bool isReadTypeFloat = false;
|
||||
int bytesPerPixel;
|
||||
int requiredDataType;
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
isReadTypeValid = true;
|
||||
bytesPerPixel = 1*channels;
|
||||
requiredDataType = js::Scalar::Uint8;
|
||||
break;
|
||||
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
||||
isReadTypeValid = true;
|
||||
bytesPerPixel = 2;
|
||||
requiredDataType = js::Scalar::Uint16;
|
||||
break;
|
||||
case LOCAL_GL_FLOAT:
|
||||
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float) ||
|
||||
IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float))
|
||||
{
|
||||
isReadTypeValid = true;
|
||||
isReadTypeFloat = true;
|
||||
bytesPerPixel = 4*channels;
|
||||
requiredDataType = js::Scalar::Float32;
|
||||
}
|
||||
break;
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
bytesPerPixel = 1*channels;
|
||||
requiredDataType = js::Scalar::Uint8;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
||||
bytesPerPixel = 2;
|
||||
requiredDataType = js::Scalar::Uint16;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_FLOAT:
|
||||
bytesPerPixel = 4*channels;
|
||||
requiredDataType = js::Scalar::Float32;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_HALF_FLOAT:
|
||||
case LOCAL_GL_HALF_FLOAT_OES:
|
||||
bytesPerPixel = 2*channels;
|
||||
requiredDataType = js::Scalar::Uint16;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("bad `type`");
|
||||
}
|
||||
if (!isReadTypeValid)
|
||||
return ErrorInvalidEnum("readPixels: Bad type", type);
|
||||
|
||||
const ArrayBufferView& pixbuf = pixels.Value();
|
||||
int dataType = JS_GetArrayBufferViewType(pixbuf.Obj());
|
||||
|
@ -1988,43 +2068,38 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
isSourceTypeFloat = false;
|
||||
}
|
||||
|
||||
if (isReadTypeFloat != isSourceTypeFloat)
|
||||
return ErrorInvalidOperation("readPixels: Invalid type floatness");
|
||||
|
||||
// Check the format and type params to assure they are an acceptable pair (as per spec)
|
||||
|
||||
bool isFormatAndTypeValid = false;
|
||||
const GLenum mainReadFormat = LOCAL_GL_RGBA;
|
||||
const GLenum mainReadType = isSourceTypeFloat ? LOCAL_GL_FLOAT
|
||||
: LOCAL_GL_UNSIGNED_BYTE;
|
||||
|
||||
GLenum auxReadFormat = mainReadFormat;
|
||||
GLenum auxReadType = mainReadType;
|
||||
|
||||
// OpenGL ES 2.0 $4.3.1 - IMPLEMENTATION_COLOR_READ_{TYPE/FORMAT} is a valid
|
||||
// combination for glReadPixels().
|
||||
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
|
||||
GLenum implType = 0;
|
||||
GLenum implFormat = 0;
|
||||
|
||||
gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE,
|
||||
reinterpret_cast<GLint*>(&implType));
|
||||
gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT,
|
||||
reinterpret_cast<GLint*>(&implFormat));
|
||||
|
||||
if (type == implType && format == implFormat) {
|
||||
isFormatAndTypeValid = true;
|
||||
}
|
||||
reinterpret_cast<GLint*>(&auxReadFormat));
|
||||
gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE,
|
||||
reinterpret_cast<GLint*>(&auxReadType));
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case LOCAL_GL_RGBA: {
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
case LOCAL_GL_FLOAT:
|
||||
isFormatAndTypeValid = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFormatAndTypeValid) {
|
||||
const bool mainMatches = (format == mainReadFormat && type == mainReadType);
|
||||
const bool auxMatches = (format == auxReadFormat && type == auxReadType);
|
||||
const bool isValid = mainMatches || auxMatches;
|
||||
if (!isValid)
|
||||
return ErrorInvalidOperation("readPixels: Invalid format/type pair");
|
||||
|
||||
GLenum readType = type;
|
||||
if (gl->WorkAroundDriverBugs() && gl->IsANGLE()) {
|
||||
if (type == LOCAL_GL_FLOAT &&
|
||||
auxReadFormat == format &&
|
||||
auxReadType == LOCAL_GL_HALF_FLOAT)
|
||||
{
|
||||
readType = auxReadType;
|
||||
}
|
||||
}
|
||||
|
||||
// Now that the errors are out of the way, on to actually reading
|
||||
|
@ -2035,7 +2110,10 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
|
||||
if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
|
||||
// the easy case: we're not reading out-of-range pixels
|
||||
gl->fReadPixels(x, y, width, height, format, type, data);
|
||||
|
||||
// Effectively: gl->fReadPixels(x, y, width, height, format, type, dest);
|
||||
ReadPixelsAndConvert(gl, x, y, width, height, format, readType,
|
||||
mPixelStorePackAlignment, format, type, data);
|
||||
} else {
|
||||
// the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part
|
||||
// of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL
|
||||
|
@ -2084,8 +2162,11 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
if (!subrect_data)
|
||||
return ErrorOutOfMemory("readPixels: subrect_data");
|
||||
|
||||
gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height,
|
||||
format, type, subrect_data.get());
|
||||
// Effectively: gl->fReadPixels(subrect_x, subrect_y, subrect_width,
|
||||
// subrect_height, format, type, subrect_data.get());
|
||||
ReadPixelsAndConvert(gl, subrect_x, subrect_y, subrect_width, subrect_height,
|
||||
format, readType, mPixelStorePackAlignment, format, type,
|
||||
subrect_data.get());
|
||||
|
||||
// notice that this for loop terminates because we already checked that subrect_height is at most height
|
||||
for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) {
|
||||
|
@ -3597,7 +3678,7 @@ mozilla::GetWebGLTexelFormat(TexInternalFormat effectiveInternalFormat)
|
|||
}
|
||||
|
||||
void
|
||||
WebGLContext::BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
|
||||
WebGLContext::BlendColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
|
||||
if (IsContextLost())
|
||||
return;
|
||||
MakeContextCurrent();
|
||||
|
|
|
@ -266,6 +266,16 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
|||
return JS::NumberValue(uint32_t(i));
|
||||
}
|
||||
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: {
|
||||
if (mBoundReadFramebuffer) {
|
||||
FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus();
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
ErrorInvalidOperation("getParameter: Read framebuffer must be"
|
||||
" complete before querying"
|
||||
" IMPLEMENTATION_COLOR_READ_TYPE.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
}
|
||||
|
||||
GLint i = 0;
|
||||
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
|
||||
gl->fGetIntegerv(pname, &i);
|
||||
|
@ -275,6 +285,16 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
|||
return JS::NumberValue(uint32_t(i));
|
||||
}
|
||||
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: {
|
||||
if (mBoundReadFramebuffer) {
|
||||
FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus();
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
ErrorInvalidOperation("getParameter: Read framebuffer must be"
|
||||
" complete before querying"
|
||||
" IMPLEMENTATION_COLOR_READ_FORMAT.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
}
|
||||
|
||||
GLint i = 0;
|
||||
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
|
||||
gl->fGetIntegerv(pname, &i);
|
||||
|
|
|
@ -26,7 +26,8 @@ WebGLExtensionColorBufferHalfFloat::IsSupported(const WebGLContext* webgl)
|
|||
gl::GLContext* gl = webgl->GL();
|
||||
|
||||
// ANGLE doesn't support ReadPixels from a RGBA16F with RGBA/FLOAT.
|
||||
return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float);
|
||||
return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float) ||
|
||||
gl->IsANGLE();
|
||||
}
|
||||
|
||||
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionColorBufferHalfFloat)
|
||||
|
|
|
@ -129,6 +129,7 @@ WebGLFramebuffer::Attachment::IsReadableFloat() const
|
|||
MOZ_ASSERT(internalformat != LOCAL_GL_NONE);
|
||||
TexType type = TypeFromInternalFormat(internalformat);
|
||||
return type == LOCAL_GL_FLOAT ||
|
||||
type == LOCAL_GL_HALF_FLOAT_OES ||
|
||||
type == LOCAL_GL_HALF_FLOAT;
|
||||
}
|
||||
|
||||
|
@ -803,6 +804,7 @@ WebGLFramebuffer::CheckFramebufferStatus() const
|
|||
// Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
|
||||
FinalizeAttachments();
|
||||
|
||||
// TODO: This should not be unconditionally GL_FRAMEBUFFER.
|
||||
mStatus = mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||
return mStatus;
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ unpackFromFloat16(uint16_t v)
|
|||
uint16_t exp = (v >> 10) & 0x001F;
|
||||
uint16_t mantissa = v & 0x03FF;
|
||||
|
||||
if (exp) {
|
||||
if (!exp) {
|
||||
// Handle denormalized numbers
|
||||
// Adapted from: OpenGL ES 2.0 Programming Guide Appx.
|
||||
// Converting Float to Half-Float
|
||||
|
|
|
@ -22,6 +22,8 @@ skip-if = android_version == '10' #Android 2.3 aws only; bug 1030942
|
|||
[webgl-mochitest/test_texsubimage_float.html]
|
||||
[webgl-mochitest/test_webgl_available.html]
|
||||
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
|
||||
#[webgl-mochitest/test_webgl_color_buffer_float.html]
|
||||
# We haven't cleaned up the Try results yet, but let's get this on the books first.
|
||||
[webgl-mochitest/test_webgl_conformance.html]
|
||||
skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
|
||||
[webgl-mochitest/test_webgl_request_context.html]
|
||||
|
|
|
@ -0,0 +1,486 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<script src='/tests/SimpleTest/SimpleTest.js'></script>
|
||||
<link rel='stylesheet' href='/tests/SimpleTest/test.css'>
|
||||
</head>
|
||||
<body>
|
||||
<script id='vs' type='x-shader/x-vertex'>
|
||||
|
||||
attribute vec2 aVertCoord;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = vec4(aVertCoord, 0.0, 1.0);
|
||||
}
|
||||
|
||||
</script>
|
||||
<script id='fs' type='x-shader/x-fragment'>
|
||||
|
||||
precision mediump float; // 💩
|
||||
|
||||
uniform vec4 uFragColor;
|
||||
|
||||
void main(void) {
|
||||
gl_FragColor = uFragColor;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<canvas id='c' width='200' height='200'></canvas>
|
||||
|
||||
<script>
|
||||
|
||||
function GetGLSLByElemId(elemId) {
|
||||
var elem = document.getElementById(elemId);
|
||||
if (!elem)
|
||||
throw 'Bad `elemId`: ' + elemId;
|
||||
|
||||
return elem.innerHTML.trim();
|
||||
}
|
||||
|
||||
function ProgramByElemIds(gl, vsId, fsId) {
|
||||
var vs = gl.createShader(gl.VERTEX_SHADER);
|
||||
gl.shaderSource(vs, GetGLSLByElemId(vsId));
|
||||
gl.compileShader(vs);
|
||||
|
||||
var fs = gl.createShader(gl.FRAGMENT_SHADER);
|
||||
gl.shaderSource(fs, GetGLSLByElemId(fsId));
|
||||
gl.compileShader(fs);
|
||||
|
||||
var prog = gl.createProgram();
|
||||
gl.attachShader(prog, vs);
|
||||
gl.attachShader(prog, fs);
|
||||
|
||||
gl.linkProgram(prog);
|
||||
|
||||
var success = gl.getProgramParameter(prog, gl.LINK_STATUS);
|
||||
if (success)
|
||||
return prog;
|
||||
|
||||
console.log('Error linking program for \'' + vsId + '\' and \'' + fsId + '\'.');
|
||||
console.log('\nLink log: ' + gl.getProgramInfoLog(prog));
|
||||
console.log('\nVert shader log: ' + gl.getShaderInfoLog(vs));
|
||||
console.log('\nFrag shader log: ' + gl.getShaderInfoLog(fs));
|
||||
return null;
|
||||
}
|
||||
|
||||
var RGBA = 0x1908;
|
||||
var UNSIGNED_BYTE = 0x1401;
|
||||
var FLOAT = 0x1406;
|
||||
var HALF_FLOAT_OES = 0x8D61;
|
||||
var HALF_FLOAT = 0x140B;
|
||||
var RGBA4 = 0x8056;
|
||||
var RGBA8 = 0x8058;
|
||||
var RGBA32F = 0x8814;
|
||||
var RGBA16F = 0x881A;
|
||||
|
||||
function EnumName(val) {
|
||||
switch (val) {
|
||||
case RGBA:
|
||||
return 'RGBA';
|
||||
case UNSIGNED_BYTE:
|
||||
return 'UNSIGNED_BYTE';
|
||||
case FLOAT:
|
||||
return 'FLOAT';
|
||||
case HALF_FLOAT_OES:
|
||||
return 'HALF_FLOAT_OES';
|
||||
case HALF_FLOAT:
|
||||
return 'HALF_FLOAT';
|
||||
case RGBA4:
|
||||
return 'RGBA4';
|
||||
case RGBA32F:
|
||||
return 'RGBA32F';
|
||||
default:
|
||||
throw 'Unknown enum: 0x' + val.toString(16);
|
||||
}
|
||||
}
|
||||
|
||||
var gl;
|
||||
|
||||
function RGBAToString(arr) {
|
||||
return '[' + arr[0].toPrecision(4) + ', ' +
|
||||
arr[1].toPrecision(4) + ', ' +
|
||||
arr[2].toPrecision(4) + ', ' +
|
||||
arr[3].toPrecision(4) + ']';
|
||||
}
|
||||
|
||||
function TestScreenColor(gl, isFBFloat, r, g, b, a) {
|
||||
var readType = isFBFloat ? FLOAT : UNSIGNED_BYTE;
|
||||
|
||||
var arr;
|
||||
switch (readType) {
|
||||
case gl.UNSIGNED_BYTE:
|
||||
arr = new Uint8Array(4);
|
||||
break;
|
||||
|
||||
case gl.FLOAT:
|
||||
arr = new Float32Array(4);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw 'Bad `readType`.';
|
||||
}
|
||||
|
||||
gl.readPixels(0, 0, 1, 1, gl.RGBA, readType, arr);
|
||||
|
||||
var err = gl.getError();
|
||||
ok(err == 0, 'Should be no errors.');
|
||||
if (err)
|
||||
return;
|
||||
|
||||
var floatArr;
|
||||
switch (readType) {
|
||||
case gl.UNSIGNED_BYTE:
|
||||
floatArr = new Float32Array(4);
|
||||
floatArr[0] = arr[0] / 255.0;
|
||||
floatArr[1] = arr[1] / 255.0;
|
||||
floatArr[2] = arr[2] / 255.0;
|
||||
floatArr[3] = arr[3] / 255.0;
|
||||
break;
|
||||
|
||||
case gl.FLOAT:
|
||||
floatArr = arr;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw 'Bad `readType`.';
|
||||
}
|
||||
|
||||
var testText = RGBAToString(floatArr);
|
||||
var refText = RGBAToString([r, g, b, a]);
|
||||
|
||||
var eps = 1.0 / 255.0;
|
||||
var isSame = (Math.abs(floatArr[0] - r) < eps &&
|
||||
Math.abs(floatArr[1] - g) < eps &&
|
||||
Math.abs(floatArr[2] - b) < eps &&
|
||||
Math.abs(floatArr[3] - a) < eps);
|
||||
|
||||
ok(isSame, 'Should be ' + refText + ', was ' + testText + ',');
|
||||
}
|
||||
|
||||
function TestReadFormat(gl, isFBFloat, format, type) {
|
||||
var err = gl.getError();
|
||||
if (err) {
|
||||
ok(false, 'Should be no error at start of TestReadFormat(). (0x' + err.toString(16) + ')');
|
||||
return;
|
||||
}
|
||||
var implFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
|
||||
var implType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
|
||||
|
||||
var err = gl.getError();
|
||||
if (err) {
|
||||
ok(false, 'Should be no error at start2 of TestReadFormat(). (0x' + err.toString(16) + ')');
|
||||
return;
|
||||
}
|
||||
|
||||
var defaultReadType = isFBFloat ? FLOAT : UNSIGNED_BYTE;
|
||||
|
||||
var formatOk = (format == gl.RGBA &&
|
||||
type == defaultReadType);
|
||||
|
||||
if (format == implFormat &&
|
||||
type == implType)
|
||||
{
|
||||
formatOk = true;
|
||||
}
|
||||
|
||||
var w = 1;
|
||||
var h = 1;
|
||||
var channels = 4;
|
||||
var arrSize = w * h * channels;
|
||||
|
||||
var arr;
|
||||
switch (type) {
|
||||
case UNSIGNED_BYTE:
|
||||
arr = new Uint8Array(arrSize);
|
||||
break;
|
||||
|
||||
case FLOAT:
|
||||
arr = new Float32Array(arrSize);
|
||||
break;
|
||||
|
||||
case HALF_FLOAT_OES:
|
||||
case HALF_FLOAT:
|
||||
arr = new Uint16Array(arrSize);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw 'Bad `type`: 0x' + type.toString(16);
|
||||
}
|
||||
|
||||
gl.readPixels(0, 0, 1, 1, format, type, arr);
|
||||
var wasOk = gl.getError() == 0;
|
||||
|
||||
var text = 'Should ' + (formatOk ? '' : 'not ') + 'allow reading with ' +
|
||||
EnumName(format) + '/' + EnumName(type) + '.'
|
||||
ok(wasOk == formatOk, text);
|
||||
}
|
||||
|
||||
function TestError(gl, expectedErr, descText) {
|
||||
var err = gl.getError();
|
||||
|
||||
while (gl.getError()) {}
|
||||
|
||||
ok(err == expectedErr,
|
||||
descText + ': Error should be 0x' + expectedErr.toString(16) + ', was 0x' +
|
||||
err.toString(16) + '.');
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
function AttachRBToCurFB(gl, sizedFormat) {
|
||||
var isSupported;
|
||||
switch (sizedFormat) {
|
||||
case RGBA4:
|
||||
isSupported = true;
|
||||
break;
|
||||
|
||||
case RGBA16F:
|
||||
isSupported = !!gl.getExtension('EXT_color_buffer_half_float');
|
||||
break;
|
||||
|
||||
case RGBA32F:
|
||||
isSupported = !!gl.getExtension('WEBGL_color_buffer_float');
|
||||
break;
|
||||
|
||||
default:
|
||||
throw 'Bad `sizedFormat`.';
|
||||
}
|
||||
|
||||
var rb = gl.createRenderbuffer();
|
||||
gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
|
||||
gl.renderbufferStorage(gl.RENDERBUFFER, sizedFormat, 1, 1);
|
||||
|
||||
var correctError = isSupported ? 0 : gl.INVALID_ENUM;
|
||||
var err = TestError(gl, correctError, 'RB specification with supported format');
|
||||
if (err)
|
||||
return false;
|
||||
|
||||
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);
|
||||
|
||||
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
|
||||
var isComplete = (status == gl.FRAMEBUFFER_COMPLETE);
|
||||
ok(isComplete, 'Framebuffer should be complete after RB attachment.');
|
||||
return isComplete;
|
||||
}
|
||||
|
||||
function AttachTexToCurFB(gl, sizedFormat) {
|
||||
var canCreate;
|
||||
var isAttachGuaranteed;
|
||||
var format;
|
||||
var type;
|
||||
|
||||
switch (sizedFormat) {
|
||||
case RGBA8:
|
||||
canCreate = true;
|
||||
isAttachGuaranteed = true;
|
||||
format = RGBA;
|
||||
type = UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
case RGBA16F:
|
||||
canCreate = !!gl.getExtension('OES_texture_half_float');
|
||||
isAttachGuaranteed = !!gl.getExtension('EXT_color_buffer_half_float');
|
||||
format = RGBA;
|
||||
type = HALF_FLOAT_OES;
|
||||
break;
|
||||
|
||||
case RGBA32F:
|
||||
canCreate = !!gl.getExtension('OES_texture_float');
|
||||
isAttachGuaranteed = !!gl.getExtension('WEBGL_color_buffer_float');
|
||||
format = RGBA;
|
||||
type = FLOAT;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw 'Bad `sizedFormat`.';
|
||||
}
|
||||
|
||||
var tex = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, format, 1, 1, 0, format, type, null);
|
||||
|
||||
var correctError = canCreate ? 0 : gl.INVALID_ENUM;
|
||||
var err = TestError(gl, correctError, 'Tex specification with supported format');
|
||||
if (err)
|
||||
return false;
|
||||
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
|
||||
|
||||
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
|
||||
var isComplete = (status == gl.FRAMEBUFFER_COMPLETE);
|
||||
|
||||
if (!isAttachGuaranteed && !isComplete)
|
||||
todo(false, 'Framebuffer needn\'t be complete after tex attachment.');
|
||||
else
|
||||
ok(isComplete, 'Framebuffer should be complete after tex attachment.');
|
||||
|
||||
return isComplete;
|
||||
}
|
||||
|
||||
function IsFormatFloat(sizedFormat) {
|
||||
switch (sizedFormat) {
|
||||
case RGBA4:
|
||||
case RGBA8:
|
||||
return false;
|
||||
|
||||
case RGBA16F:
|
||||
case RGBA32F:
|
||||
return true;
|
||||
|
||||
default:
|
||||
throw 'Bad `sizedFormat`.';
|
||||
}
|
||||
}
|
||||
|
||||
function TestType(gl, prog, isTex, sizedFormat) {
|
||||
TestError(gl, 0, 'At start of TestRB()');
|
||||
|
||||
var isAttached = isTex ? AttachTexToCurFB(gl, sizedFormat)
|
||||
: AttachRBToCurFB(gl, sizedFormat);
|
||||
if (!isAttached)
|
||||
return;
|
||||
|
||||
var isFormatFloat = IsFormatFloat(sizedFormat);
|
||||
|
||||
TestReadFormat(gl, isFormatFloat, gl.RGBA, gl.UNSIGNED_BYTE);
|
||||
TestReadFormat(gl, isFormatFloat, gl.RGBA, gl.FLOAT);
|
||||
TestReadFormat(gl, isFormatFloat, gl.RGBA, HALF_FLOAT);
|
||||
TestReadFormat(gl, isFormatFloat, gl.RGBA, HALF_FLOAT_OES);
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
ok(true, 'Drawing:');
|
||||
|
||||
gl.clearColor(0.0, 1.5, 0.5, 1.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
if (isFormatFloat)
|
||||
TestScreenColor(gl, isFormatFloat, 0, 1.5, 0.5, 1);
|
||||
else
|
||||
TestScreenColor(gl, isFormatFloat, 0, 1, 0.5, 1);
|
||||
|
||||
////////
|
||||
|
||||
ok(true, 'Clearing:');
|
||||
|
||||
gl.uniform4f(prog.uFragColor, 0, 0.5, 1.5, 1);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
if (isFormatFloat)
|
||||
TestScreenColor(gl, isFormatFloat, 0, 0.5, 1.5, 1);
|
||||
else
|
||||
TestScreenColor(gl, isFormatFloat, 0, 0.5, 1.0, 1);
|
||||
|
||||
////////
|
||||
|
||||
ok(true, 'Blending:');
|
||||
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendFunc(gl.CONSTANT_COLOR, gl.ZERO);
|
||||
gl.blendColor(0, 10, 0.1, 1);
|
||||
|
||||
gl.uniform4f(prog.uFragColor, 0, 0.5, 15.0, 1);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
if (isFormatFloat)
|
||||
TestScreenColor(gl, isFormatFloat, 0, 5.0, 1.5, 1);
|
||||
else
|
||||
TestScreenColor(gl, isFormatFloat, 0, 0.5, 0.1, 1);
|
||||
|
||||
gl.disable(gl.BLEND);
|
||||
|
||||
//////////////////////////////////////
|
||||
}
|
||||
|
||||
// Give ourselves a scope to return early from:
|
||||
(function() {
|
||||
var canvas = document.getElementById('c');
|
||||
var attribs = {
|
||||
antialias: false,
|
||||
depth: false,
|
||||
};
|
||||
gl = canvas.getContext('experimental-webgl', attribs);
|
||||
if (!gl) {
|
||||
todo(false, 'WebGL is unavailable.');
|
||||
return;
|
||||
}
|
||||
|
||||
var cbf = gl.getExtension('WEBGL_color_buffer_float');
|
||||
var cbhf = gl.getExtension('EXT_color_buffer_half_float');
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
gl.viewport(0, 0, 1, 1);
|
||||
|
||||
var prog = ProgramByElemIds(gl, 'vs', 'fs');
|
||||
ok(prog, 'Program should link.');
|
||||
if (!prog)
|
||||
return;
|
||||
|
||||
prog.aVertCoord = gl.getAttribLocation(prog, 'aVertCoord');
|
||||
prog.uFragColor = gl.getUniformLocation(prog, 'uFragColor');
|
||||
|
||||
gl.useProgram(prog);
|
||||
|
||||
var arr = new Float32Array([
|
||||
-1, -1,
|
||||
1, -1,
|
||||
-1, 1,
|
||||
1, 1,
|
||||
]);
|
||||
var vb = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vb);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW);
|
||||
|
||||
gl.enableVertexAttribArray(0);
|
||||
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
var fb = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
|
||||
|
||||
error = gl.getError();
|
||||
ok(error == 0, 'Should be no errors after setup. (0x' + error.toString(16) + ')');
|
||||
|
||||
//////////////////////////////////////
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
ok(true, 'RGBA8 texture');
|
||||
TestType(gl, prog, true, RGBA8);
|
||||
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
ok(true, 'RGBA16F texture');
|
||||
TestType(gl, prog, true, RGBA16F);
|
||||
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
ok(true, 'RGBA32F texture');
|
||||
TestType(gl, prog, true, RGBA32F);
|
||||
|
||||
////////
|
||||
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
ok(true, 'RGBA4 renderbuffer');
|
||||
TestType(gl, prog, false, RGBA4);
|
||||
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
ok(true, 'RGBA16F renderbuffer');
|
||||
TestType(gl, prog, false, RGBA16F);
|
||||
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
ok(true, 'RGBA32F renderbuffer');
|
||||
TestType(gl, prog, false, RGBA32F);
|
||||
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
//////////////////////////////////////
|
||||
|
||||
error = gl.getError();
|
||||
ok(error == 0, 'Should be no errors after test.');
|
||||
|
||||
ok(true, 'TEST COMPLETE');
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -520,7 +520,7 @@ interface WebGLRenderingContext {
|
|||
void bindFramebuffer(GLenum target, WebGLFramebuffer? framebuffer);
|
||||
void bindRenderbuffer(GLenum target, WebGLRenderbuffer? renderbuffer);
|
||||
void bindTexture(GLenum target, WebGLTexture? texture);
|
||||
void blendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
|
||||
void blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
void blendEquation(GLenum mode);
|
||||
void blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
|
||||
void blendFunc(GLenum sfactor, GLenum dfactor);
|
||||
|
@ -535,7 +535,7 @@ interface WebGLRenderingContext {
|
|||
|
||||
[WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target);
|
||||
void clear(GLbitfield mask);
|
||||
void clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
|
||||
void clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
void clearDepth(GLclampf depth);
|
||||
void clearStencil(GLint s);
|
||||
void colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
|
||||
|
|
|
@ -295,7 +295,7 @@ void GL_APIENTRY glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLcla
|
|||
|
||||
if (context)
|
||||
{
|
||||
context->getState().setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha));
|
||||
context->getState().setBlendColor(red, green, blue, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -886,7 +886,7 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
|
||||
void fBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fBlendColor(red, green, blue, alpha);
|
||||
AFTER_GL_CALL;
|
||||
|
@ -986,7 +986,7 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
|
||||
void fClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fClearColor(r, g, b, a);
|
||||
AFTER_GL_CALL;
|
||||
|
|
|
@ -49,7 +49,7 @@ struct GLContextSymbols
|
|||
PFNGLBINDTEXTUREPROC fBindTexture;
|
||||
typedef void (GLAPIENTRY * PFNGLBINDVERTEXARRAYPROC) (GLuint array);
|
||||
PFNGLBINDVERTEXARRAYPROC fBindVertexArray;
|
||||
typedef void (GLAPIENTRY * PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
|
||||
typedef void (GLAPIENTRY * PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
PFNGLBLENDCOLORPROC fBlendColor;
|
||||
typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONPROC) (GLenum mode);
|
||||
PFNGLBLENDEQUATIONPROC fBlendEquation;
|
||||
|
@ -73,7 +73,7 @@ struct GLContextSymbols
|
|||
PFNGLCLEARBUFFERIVPROC fClearBufferiv;
|
||||
typedef void (GLAPIENTRY * PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint* value);
|
||||
PFNGLCLEARBUFFERUIVPROC fClearBufferuiv;
|
||||
typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLclampf, GLclampf, GLclampf, GLclampf);
|
||||
typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLfloat, GLfloat, GLfloat, GLfloat);
|
||||
PFNGLCLEARCOLORPROC fClearColor;
|
||||
typedef void (GLAPIENTRY * PFNGLCLEARSTENCILPROC) (GLint);
|
||||
PFNGLCLEARSTENCILPROC fClearStencil;
|
||||
|
|
Загрузка…
Ссылка в новой задаче