Bug 1130616 - Support EXT_color_buffer_half_float on ANGLE. - r=jrmuizel,khuey

This commit is contained in:
Jeff Gilbert 2015-02-24 14:09:09 -08:00
Родитель ad69b19ecc
Коммит 75d555e953
14 изменённых файлов: 700 добавлений и 91 удалений

Просмотреть файл

@ -1852,6 +1852,12 @@ WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget,
return ok; 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) WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl)
@ -1875,6 +1881,7 @@ WebGLContext::ScopedMaskWorkaround::~ScopedMaskWorkaround()
mWebGL.mColorWriteMask[3]); mWebGL.mColorWriteMask[3]);
} }
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// XPCOM goop // XPCOM goop

Просмотреть файл

@ -1092,9 +1092,7 @@ protected:
GLenum pname); GLenum pname);
// Returns x rounded to the next highest multiple of y. // Returns x rounded to the next highest multiple of y.
static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y) {
CheckedUint32 y)
{
return ((x + y - 1) / y) * y; return ((x + y - 1) / y) * y;
} }
@ -1693,6 +1691,8 @@ private:
WebGLContext* mWebGL; WebGLContext* mWebGL;
}; };
size_t RoundUpToMultipleOf(size_t value, size_t multiple);
} // namespace mozilla } // namespace mozilla
#endif #endif

Просмотреть файл

@ -49,8 +49,8 @@ WebGLContext::Clear(GLbitfield mask)
mShouldPresent = true; mShouldPresent = true;
} }
static GLclampf static GLfloat
GLClampFloat(GLclampf val) GLClampFloat(GLfloat val)
{ {
if (val < 0.0) if (val < 0.0)
return 0.0; return 0.0;
@ -62,18 +62,28 @@ GLClampFloat(GLclampf val)
} }
void void
WebGLContext::ClearColor(GLclampf r, GLclampf g, WebGLContext::ClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
GLclampf b, GLclampf a)
{ {
if (IsContextLost()) if (IsContextLost())
return; return;
MakeContextCurrent(); MakeContextCurrent();
mColorClearValue[0] = GLClampFloat(r);
mColorClearValue[1] = GLClampFloat(g); const bool supportsFloatColorBuffers = (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) ||
mColorClearValue[2] = GLClampFloat(b); IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float));
mColorClearValue[3] = GLClampFloat(a); if (!supportsFloatColorBuffers) {
r = GLClampFloat(r);
g = GLClampFloat(g);
b = GLClampFloat(b);
a = GLClampFloat(a);
}
gl->fClearColor(r, g, b, a); gl->fClearColor(r, g, b, a);
mColorClearValue[0] = r;
mColorClearValue[1] = g;
mColorClearValue[2] = b;
mColorClearValue[3] = a;
} }
void void

Просмотреть файл

@ -1863,6 +1863,84 @@ SetFullAlpha(void* data, GLenum format, GLenum type, size_t width,
return false; 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 void
WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
GLsizei height, GLenum format, GLsizei height, GLenum format,
@ -1883,59 +1961,61 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
if (pixels.IsNull()) if (pixels.IsNull())
return ErrorInvalidValue("readPixels: null destination buffer"); return ErrorInvalidValue("readPixels: null destination buffer");
if (!IsFormatAndTypeUnpackable(format, type))
return ErrorInvalidEnum("readPixels: Bad format or type.");
const WebGLRectangleObject* framebufferRect = CurValidReadFBRectObject(); const WebGLRectangleObject* framebufferRect = CurValidReadFBRectObject();
GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0; GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0; GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
uint32_t channels = 0; int channels = 0;
// Check the format param // Check the format param
switch (format) { switch (format) {
case LOCAL_GL_ALPHA: case LOCAL_GL_ALPHA:
channels = 1; channels = 1;
break; break;
case LOCAL_GL_RGB: case LOCAL_GL_RGB:
channels = 3; channels = 3;
break; break;
case LOCAL_GL_RGBA: case LOCAL_GL_RGBA:
channels = 4; channels = 4;
break; break;
default: default:
return ErrorInvalidEnum("readPixels: Bad format"); MOZ_CRASH("bad `format`");
} }
uint32_t bytesPerPixel = 0;
int requiredDataType = 0;
// Check the type param // Check the type param
bool isReadTypeValid = false; int bytesPerPixel;
bool isReadTypeFloat = false; int requiredDataType;
switch (type) { switch (type) {
case LOCAL_GL_UNSIGNED_BYTE: case LOCAL_GL_UNSIGNED_BYTE:
isReadTypeValid = true; bytesPerPixel = 1*channels;
bytesPerPixel = 1*channels; requiredDataType = js::Scalar::Uint8;
requiredDataType = js::Scalar::Uint8; break;
break;
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4: case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1: case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
case LOCAL_GL_UNSIGNED_SHORT_5_6_5: case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
isReadTypeValid = true; bytesPerPixel = 2;
bytesPerPixel = 2; requiredDataType = js::Scalar::Uint16;
requiredDataType = js::Scalar::Uint16; break;
break;
case LOCAL_GL_FLOAT: case LOCAL_GL_FLOAT:
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float) || bytesPerPixel = 4*channels;
IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float)) requiredDataType = js::Scalar::Float32;
{ break;
isReadTypeValid = true;
isReadTypeFloat = true; case LOCAL_GL_HALF_FLOAT:
bytesPerPixel = 4*channels; case LOCAL_GL_HALF_FLOAT_OES:
requiredDataType = js::Scalar::Float32; bytesPerPixel = 2*channels;
} requiredDataType = js::Scalar::Uint16;
break; break;
default:
MOZ_CRASH("bad `type`");
} }
if (!isReadTypeValid)
return ErrorInvalidEnum("readPixels: Bad type", type);
const ArrayBufferView& pixbuf = pixels.Value(); const ArrayBufferView& pixbuf = pixels.Value();
int dataType = JS_GetArrayBufferViewType(pixbuf.Obj()); int dataType = JS_GetArrayBufferViewType(pixbuf.Obj());
@ -1988,43 +2068,38 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
isSourceTypeFloat = false; 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) // 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 // OpenGL ES 2.0 $4.3.1 - IMPLEMENTATION_COLOR_READ_{TYPE/FORMAT} is a valid
// combination for glReadPixels(). // combination for glReadPixels().
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) { 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, gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT,
reinterpret_cast<GLint*>(&implFormat)); reinterpret_cast<GLint*>(&auxReadFormat));
gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE,
if (type == implType && format == implFormat) { reinterpret_cast<GLint*>(&auxReadType));
isFormatAndTypeValid = true;
}
} }
switch (format) { const bool mainMatches = (format == mainReadFormat && type == mainReadType);
case LOCAL_GL_RGBA: { const bool auxMatches = (format == auxReadFormat && type == auxReadType);
switch (type) { const bool isValid = mainMatches || auxMatches;
case LOCAL_GL_UNSIGNED_BYTE: if (!isValid)
case LOCAL_GL_FLOAT:
isFormatAndTypeValid = true;
break;
}
break;
}
}
if (!isFormatAndTypeValid) {
return ErrorInvalidOperation("readPixels: Invalid format/type pair"); 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 // 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)) { if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
// the easy case: we're not reading out-of-range pixels // 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 { } else {
// the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part // 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 // 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) if (!subrect_data)
return ErrorOutOfMemory("readPixels: subrect_data"); return ErrorOutOfMemory("readPixels: subrect_data");
gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height, // Effectively: gl->fReadPixels(subrect_x, subrect_y, subrect_width,
format, type, subrect_data.get()); // 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 // 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) { for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) {
@ -3597,7 +3678,7 @@ mozilla::GetWebGLTexelFormat(TexInternalFormat effectiveInternalFormat)
} }
void void
WebGLContext::BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) { WebGLContext::BlendColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
if (IsContextLost()) if (IsContextLost())
return; return;
MakeContextCurrent(); MakeContextCurrent();

Просмотреть файл

@ -266,6 +266,16 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
return JS::NumberValue(uint32_t(i)); return JS::NumberValue(uint32_t(i));
} }
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: { 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; GLint i = 0;
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) { if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
gl->fGetIntegerv(pname, &i); gl->fGetIntegerv(pname, &i);
@ -275,6 +285,16 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
return JS::NumberValue(uint32_t(i)); return JS::NumberValue(uint32_t(i));
} }
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: { 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; GLint i = 0;
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) { if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
gl->fGetIntegerv(pname, &i); gl->fGetIntegerv(pname, &i);

Просмотреть файл

@ -26,7 +26,8 @@ WebGLExtensionColorBufferHalfFloat::IsSupported(const WebGLContext* webgl)
gl::GLContext* gl = webgl->GL(); gl::GLContext* gl = webgl->GL();
// ANGLE doesn't support ReadPixels from a RGBA16F with RGBA/FLOAT. // 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) IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionColorBufferHalfFloat)

Просмотреть файл

@ -129,6 +129,7 @@ WebGLFramebuffer::Attachment::IsReadableFloat() const
MOZ_ASSERT(internalformat != LOCAL_GL_NONE); MOZ_ASSERT(internalformat != LOCAL_GL_NONE);
TexType type = TypeFromInternalFormat(internalformat); TexType type = TypeFromInternalFormat(internalformat);
return type == LOCAL_GL_FLOAT || return type == LOCAL_GL_FLOAT ||
type == LOCAL_GL_HALF_FLOAT_OES ||
type == LOCAL_GL_HALF_FLOAT; type == LOCAL_GL_HALF_FLOAT;
} }
@ -803,6 +804,7 @@ WebGLFramebuffer::CheckFramebufferStatus() const
// Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}. // Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
FinalizeAttachments(); FinalizeAttachments();
// TODO: This should not be unconditionally GL_FRAMEBUFFER.
mStatus = mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); mStatus = mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
return mStatus; return mStatus;
} }

Просмотреть файл

@ -105,7 +105,7 @@ unpackFromFloat16(uint16_t v)
uint16_t exp = (v >> 10) & 0x001F; uint16_t exp = (v >> 10) & 0x001F;
uint16_t mantissa = v & 0x03FF; uint16_t mantissa = v & 0x03FF;
if (exp) { if (!exp) {
// Handle denormalized numbers // Handle denormalized numbers
// Adapted from: OpenGL ES 2.0 Programming Guide Appx. // Adapted from: OpenGL ES 2.0 Programming Guide Appx.
// Converting Float to Half-Float // 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_texsubimage_float.html]
[webgl-mochitest/test_webgl_available.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 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] [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 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] [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 bindFramebuffer(GLenum target, WebGLFramebuffer? framebuffer);
void bindRenderbuffer(GLenum target, WebGLRenderbuffer? renderbuffer); void bindRenderbuffer(GLenum target, WebGLRenderbuffer? renderbuffer);
void bindTexture(GLenum target, WebGLTexture? texture); 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 blendEquation(GLenum mode);
void blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha); void blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
void blendFunc(GLenum sfactor, GLenum dfactor); void blendFunc(GLenum sfactor, GLenum dfactor);
@ -535,7 +535,7 @@ interface WebGLRenderingContext {
[WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target); [WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target);
void clear(GLbitfield mask); 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 clearDepth(GLclampf depth);
void clearStencil(GLint s); void clearStencil(GLint s);
void colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); 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) 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; 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; BEFORE_GL_CALL;
mSymbols.fBlendColor(red, green, blue, alpha); mSymbols.fBlendColor(red, green, blue, alpha);
AFTER_GL_CALL; AFTER_GL_CALL;
@ -986,7 +986,7 @@ public:
AFTER_GL_CALL; 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; BEFORE_GL_CALL;
mSymbols.fClearColor(r, g, b, a); mSymbols.fClearColor(r, g, b, a);
AFTER_GL_CALL; AFTER_GL_CALL;

Просмотреть файл

@ -49,7 +49,7 @@ struct GLContextSymbols
PFNGLBINDTEXTUREPROC fBindTexture; PFNGLBINDTEXTUREPROC fBindTexture;
typedef void (GLAPIENTRY * PFNGLBINDVERTEXARRAYPROC) (GLuint array); typedef void (GLAPIENTRY * PFNGLBINDVERTEXARRAYPROC) (GLuint array);
PFNGLBINDVERTEXARRAYPROC fBindVertexArray; 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; PFNGLBLENDCOLORPROC fBlendColor;
typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONPROC) (GLenum mode); typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONPROC) (GLenum mode);
PFNGLBLENDEQUATIONPROC fBlendEquation; PFNGLBLENDEQUATIONPROC fBlendEquation;
@ -73,7 +73,7 @@ struct GLContextSymbols
PFNGLCLEARBUFFERIVPROC fClearBufferiv; PFNGLCLEARBUFFERIVPROC fClearBufferiv;
typedef void (GLAPIENTRY * PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint* value); typedef void (GLAPIENTRY * PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint* value);
PFNGLCLEARBUFFERUIVPROC fClearBufferuiv; PFNGLCLEARBUFFERUIVPROC fClearBufferuiv;
typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLclampf, GLclampf, GLclampf, GLclampf); typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLfloat, GLfloat, GLfloat, GLfloat);
PFNGLCLEARCOLORPROC fClearColor; PFNGLCLEARCOLORPROC fClearColor;
typedef void (GLAPIENTRY * PFNGLCLEARSTENCILPROC) (GLint); typedef void (GLAPIENTRY * PFNGLCLEARSTENCILPROC) (GLint);
PFNGLCLEARSTENCILPROC fClearStencil; PFNGLCLEARSTENCILPROC fClearStencil;