Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ backend.
| `WEBGL_draw_buffers` | Exposed |
| `WEBGL_lose_context` | Exposed |
| `EXT_disjoint_timer_query` / `EXT_disjoint_timer_query_webgl2` | Not exposed |
| `WEBGL_compressed_texture_s3tc` / `WEBGL_compressed_texture_s3tc_srgb` | Not exposed |
| `WEBGL_compressed_texture_s3tc` / `WEBGL_compressed_texture_s3tc_srgb` | Exposed |

## Install

Expand Down
2 changes: 2 additions & 0 deletions binding/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ static napi_value InitBinding(napi_env env, napi_value exports) {
OESTextureHalfFloatLinearExtension::Register(env, exports);
WebGLDebugRendererInfoExtension::Register(env, exports);
WebGLDepthTextureExtension::Register(env, exports);
WebGLCompressedTextureS3TCExtension::Register(env, exports);
WebGLCompressedTextureS3TCSRGBExtension::Register(env, exports);
WebGLLoseContextExtension::Register(env, exports);
WebGLRenderingContext::Register(env, exports);

Expand Down
175 changes: 175 additions & 0 deletions binding/webgl_extensions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,59 @@ static void RequestExtensionIfAvailable(EGLContextWrapper* egl_context_wrapper,
}
}

static bool IsExtensionAvailable(EGLContextWrapper* egl_context_wrapper,
const char* ext_name) {
return egl_context_wrapper->angle_requestable_extensions->HasExtension(
ext_name) ||
egl_context_wrapper->gl_extensions->HasExtension(ext_name);
}

static bool IsAnyExtensionAvailable(EGLContextWrapper* egl_context_wrapper,
const char* const* ext_names,
size_t ext_count) {
for (size_t i = 0; i < ext_count; ++i) {
if (IsExtensionAvailable(egl_context_wrapper, ext_names[i])) {
return true;
}
}
return false;
}

static bool IsS3TCTextureCompressionSupported(
EGLContextWrapper* egl_context_wrapper) {
static const char* kDxt1Extensions[] = {
"GL_EXT_texture_compression_s3tc",
"GL_EXT_texture_compression_dxt1",
};
static const char* kDxt3Extensions[] = {
"GL_EXT_texture_compression_s3tc",
"GL_ANGLE_texture_compression_dxt3",
};
static const char* kDxt5Extensions[] = {
"GL_EXT_texture_compression_s3tc",
"GL_ANGLE_texture_compression_dxt5",
};

return IsAnyExtensionAvailable(egl_context_wrapper, kDxt1Extensions,
ARRAY_SIZE(kDxt1Extensions)) &&
IsAnyExtensionAvailable(egl_context_wrapper, kDxt3Extensions,
ARRAY_SIZE(kDxt3Extensions)) &&
IsAnyExtensionAvailable(egl_context_wrapper, kDxt5Extensions,
ARRAY_SIZE(kDxt5Extensions));
}

static void RequestS3TCTextureCompressionExtensions(
EGLContextWrapper* egl_context_wrapper) {
RequestExtensionIfAvailable(egl_context_wrapper,
"GL_EXT_texture_compression_s3tc");
RequestExtensionIfAvailable(egl_context_wrapper,
"GL_EXT_texture_compression_dxt1");
RequestExtensionIfAvailable(egl_context_wrapper,
"GL_ANGLE_texture_compression_dxt3");
RequestExtensionIfAvailable(egl_context_wrapper,
"GL_ANGLE_texture_compression_dxt5");
}

//==============================================================================
// GLExtensionBase

Expand Down Expand Up @@ -959,6 +1012,128 @@ napi_status WebGLDepthTextureExtension::NewInstance(
return napi_ok;
}

//==============================================================================
// WebGLCompressedTextureS3TCExtension

napi_ref WebGLCompressedTextureS3TCExtension::constructor_ref_;

WebGLCompressedTextureS3TCExtension::WebGLCompressedTextureS3TCExtension(
napi_env env)
: GLExtensionBase(env) {}

/* static */
bool WebGLCompressedTextureS3TCExtension::IsSupported(
EGLContextWrapper* egl_context_wrapper) {
return IsS3TCTextureCompressionSupported(egl_context_wrapper);
}

/* static */
napi_status WebGLCompressedTextureS3TCExtension::Register(napi_env env,
napi_value exports) {
napi_status nstatus;

napi_property_descriptor properties[] = {
NapiDefineIntProperty(env, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
"COMPRESSED_RGB_S3TC_DXT1_EXT"),
NapiDefineIntProperty(env, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
"COMPRESSED_RGBA_S3TC_DXT1_EXT"),
NapiDefineIntProperty(env, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
"COMPRESSED_RGBA_S3TC_DXT3_EXT"),
NapiDefineIntProperty(env, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
"COMPRESSED_RGBA_S3TC_DXT5_EXT"),
};

napi_value ctor_value;
nstatus =
napi_define_class(env, "WEBGL_compressed_texture_s3tc", NAPI_AUTO_LENGTH,
GLExtensionBase::InitStubClass, nullptr,
ARRAY_SIZE(properties), properties, &ctor_value);
ENSURE_NAPI_OK_RETVAL(env, nstatus, nstatus);

nstatus = napi_create_reference(env, ctor_value, 1, &constructor_ref_);
ENSURE_NAPI_OK_RETVAL(env, nstatus, nstatus);

return napi_ok;
}

/* static */
napi_status WebGLCompressedTextureS3TCExtension::NewInstance(
napi_env env, napi_value* instance,
EGLContextWrapper* egl_context_wrapper) {
ENSURE_EXTENSION_IS_SUPPORTED

napi_status nstatus = NewInstanceBase(env, constructor_ref_, instance);
ENSURE_NAPI_OK_RETVAL(env, nstatus, nstatus);

RequestS3TCTextureCompressionExtensions(egl_context_wrapper);
egl_context_wrapper->RefreshGLExtensions();

return napi_ok;
}

//==============================================================================
// WebGLCompressedTextureS3TCSRGBExtension

napi_ref WebGLCompressedTextureS3TCSRGBExtension::constructor_ref_;

WebGLCompressedTextureS3TCSRGBExtension::
WebGLCompressedTextureS3TCSRGBExtension(napi_env env)
: GLExtensionBase(env) {}

/* static */
bool WebGLCompressedTextureS3TCSRGBExtension::IsSupported(
EGLContextWrapper* egl_context_wrapper) {
return IsS3TCTextureCompressionSupported(egl_context_wrapper) &&
IsExtensionAvailable(egl_context_wrapper,
"GL_EXT_texture_compression_s3tc_srgb");
}

/* static */
napi_status WebGLCompressedTextureS3TCSRGBExtension::Register(
napi_env env, napi_value exports) {
napi_status nstatus;

napi_property_descriptor properties[] = {
NapiDefineIntProperty(env, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,
"COMPRESSED_SRGB_S3TC_DXT1_EXT"),
NapiDefineIntProperty(env, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,
"COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT"),
NapiDefineIntProperty(env, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,
"COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT"),
NapiDefineIntProperty(env, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,
"COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT"),
};

napi_value ctor_value;
nstatus = napi_define_class(env, "WEBGL_compressed_texture_s3tc_srgb",
NAPI_AUTO_LENGTH, GLExtensionBase::InitStubClass,
nullptr, ARRAY_SIZE(properties), properties,
&ctor_value);
ENSURE_NAPI_OK_RETVAL(env, nstatus, nstatus);

nstatus = napi_create_reference(env, ctor_value, 1, &constructor_ref_);
ENSURE_NAPI_OK_RETVAL(env, nstatus, nstatus);

return napi_ok;
}

/* static */
napi_status WebGLCompressedTextureS3TCSRGBExtension::NewInstance(
napi_env env, napi_value* instance,
EGLContextWrapper* egl_context_wrapper) {
ENSURE_EXTENSION_IS_SUPPORTED

napi_status nstatus = NewInstanceBase(env, constructor_ref_, instance);
ENSURE_NAPI_OK_RETVAL(env, nstatus, nstatus);

RequestS3TCTextureCompressionExtensions(egl_context_wrapper);
RequestExtensionIfAvailable(egl_context_wrapper,
"GL_EXT_texture_compression_s3tc_srgb");
egl_context_wrapper->RefreshGLExtensions();

return napi_ok;
}

//==============================================================================
// WebGLLoseContextExtension

Expand Down
20 changes: 20 additions & 0 deletions binding/webgl_extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,26 @@ class WebGLDepthTextureExtension : public GLExtensionBase {
virtual ~WebGLDepthTextureExtension() {}
};

// Provides 'WEBGL_compressed_texture_s3tc':
// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_s3tc/
class WebGLCompressedTextureS3TCExtension : public GLExtensionBase {
NAPI_BOOTSTRAP_METHODS

protected:
WebGLCompressedTextureS3TCExtension(napi_env env);
virtual ~WebGLCompressedTextureS3TCExtension() {}
};

// Provides 'WEBGL_compressed_texture_s3tc_srgb':
// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_s3tc_srgb/
class WebGLCompressedTextureS3TCSRGBExtension : public GLExtensionBase {
NAPI_BOOTSTRAP_METHODS

protected:
WebGLCompressedTextureS3TCSRGBExtension(napi_env env);
virtual ~WebGLCompressedTextureS3TCSRGBExtension() {}
};

// Provides the 'WEBGL_lose_context' extension:
// https://www.khronos.org/registry/webgl/extensions/WEBGL_lose_context/
class WebGLLoseContextExtension : public GLExtensionBase {
Expand Down
8 changes: 8 additions & 0 deletions binding/webgl_rendering_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6320,6 +6320,10 @@ DEFINE_EXTENSION_DESCRIPTOR_HELPERS(WebGLDebugRendererInfo,
WebGLDebugRendererInfoExtension)
DEFINE_EXTENSION_DESCRIPTOR_HELPERS(WebGLDepthTexture,
WebGLDepthTextureExtension)
DEFINE_EXTENSION_DESCRIPTOR_HELPERS(WebGLCompressedTextureS3TC,
WebGLCompressedTextureS3TCExtension)
DEFINE_EXTENSION_DESCRIPTOR_HELPERS(WebGLCompressedTextureS3TCSRGB,
WebGLCompressedTextureS3TCSRGBExtension)

#undef DEFINE_EXTENSION_DESCRIPTOR_HELPERS

Expand Down Expand Up @@ -6371,6 +6375,10 @@ static const WebGLExtensionDescriptor kKnownWebGLExtensions[] = {
{"WEBGL_debug_renderer_info", SupportsWebGLDebugRendererInfo,
NewWebGLDebugRendererInfo},
{"WEBGL_depth_texture", SupportsWebGLDepthTexture, NewWebGLDepthTexture},
{"WEBGL_compressed_texture_s3tc", SupportsWebGLCompressedTextureS3TC,
NewWebGLCompressedTextureS3TC},
{"WEBGL_compressed_texture_s3tc_srgb",
SupportsWebGLCompressedTextureS3TCSRGB, NewWebGLCompressedTextureS3TCSRGB},
{"WEBGL_draw_buffers", SupportsWEBGLDrawBuffers, NewWEBGLDrawBuffers},
{"WEBGL_lose_context", WebGLLoseContextExtension::IsSupported,
NewWebGLLoseContext},
Expand Down
18 changes: 18 additions & 0 deletions src/binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,20 @@ export type NodeGlesWEBGLDepthTexture = {
readonly UNSIGNED_INT_24_8_WEBGL: number;
};

export type NodeGlesWEBGLCompressedTextureS3TC = {
readonly COMPRESSED_RGB_S3TC_DXT1_EXT: number;
readonly COMPRESSED_RGBA_S3TC_DXT1_EXT: number;
readonly COMPRESSED_RGBA_S3TC_DXT3_EXT: number;
readonly COMPRESSED_RGBA_S3TC_DXT5_EXT: number;
};

export type NodeGlesWEBGLCompressedTextureS3TCSRGB = {
readonly COMPRESSED_SRGB_S3TC_DXT1_EXT: number;
readonly COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: number;
readonly COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: number;
readonly COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: number;
};

export type NodeGlesWEBGLLoseContext = {
loseContext(): void;
restoreContext(): void;
Expand Down Expand Up @@ -282,6 +296,10 @@ export type NodeGlesWebGL2RenderingContext = WebGL2RenderingContext & {
NodeGlesWEBGLDebugRendererInfo | null;
getExtension(extensionName: "WEBGL_depth_texture"):
NodeGlesWEBGLDepthTexture | null;
getExtension(extensionName: "WEBGL_compressed_texture_s3tc"):
NodeGlesWEBGLCompressedTextureS3TC | null;
getExtension(extensionName: "WEBGL_compressed_texture_s3tc_srgb"):
NodeGlesWEBGLCompressedTextureS3TCSRGB | null;
getExtension(extensionName: "WEBGL_draw_buffers"):
NodeGlesWEBGLDrawBuffers | null;
getExtension(extensionName: "WEBGL_lose_context"):
Expand Down
88 changes: 88 additions & 0 deletions test/webgl2-smoke.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@ function testSupportedExtensionsReflectGetExtension(gl) {
"OES_vertex_array_object",
"WEBGL_debug_renderer_info",
"WEBGL_depth_texture",
"WEBGL_compressed_texture_s3tc",
"WEBGL_compressed_texture_s3tc_srgb",
"WEBGL_draw_buffers",
"WEBGL_lose_context"
];
Expand Down Expand Up @@ -359,6 +361,91 @@ function testSupportedExtensionsReflectGetExtension(gl) {
assertNoError(gl, "getExtension browser-compatible names");
}

function testCompressedTextureS3TC(gl) {
const supported = gl.getSupportedExtensions();
const s3tc = gl.getExtension("WEBGL_compressed_texture_s3tc");
const s3tcSRGB = gl.getExtension("WEBGL_compressed_texture_s3tc_srgb");
assert.strictEqual(
supported.includes("WEBGL_compressed_texture_s3tc"), s3tc !== null,
"WEBGL_compressed_texture_s3tc support should match getExtension");
assert.strictEqual(
supported.includes("WEBGL_compressed_texture_s3tc_srgb"),
s3tcSRGB !== null,
"WEBGL_compressed_texture_s3tc_srgb support should match getExtension");

if (!s3tc) {
assert.strictEqual(
s3tcSRGB, null,
"WEBGL_compressed_texture_s3tc_srgb requires base S3TC support");
assertNoError(gl, "WEBGL_compressed_texture_s3tc unsupported path");
return;
}

const s3tcFormats = [
["COMPRESSED_RGB_S3TC_DXT1_EXT", 0x83f0, 8],
["COMPRESSED_RGBA_S3TC_DXT1_EXT", 0x83f1, 8],
["COMPRESSED_RGBA_S3TC_DXT3_EXT", 0x83f2, 16],
["COMPRESSED_RGBA_S3TC_DXT5_EXT", 0x83f3, 16]
];
const compressedFormats =
new Set(gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS));
for (const [name, value] of s3tcFormats) {
assert.strictEqual(s3tc[name], value, `${name} constant`);
assert(
compressedFormats.has(value),
`${name} should be listed in COMPRESSED_TEXTURE_FORMATS`);
}

const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
for (const [name, , byteLength] of s3tcFormats) {
gl.compressedTexImage2D(
gl.TEXTURE_2D, 0, s3tc[name], 4, 4, 0,
new Uint8Array(byteLength));
assertNoError(gl, `${name} compressedTexImage2D`);
}
gl.deleteTexture(texture);

if (!s3tcSRGB) {
assertNoError(gl, "WEBGL_compressed_texture_s3tc smoke");
return;
}

const s3tcSRGBFormats = [
["COMPRESSED_SRGB_S3TC_DXT1_EXT", 0x8c4c, 8],
["COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT", 0x8c4d, 8],
["COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT", 0x8c4e, 16],
["COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT", 0x8c4f, 16]
];
const srgbCompressedFormats =
new Set(gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS));
for (const [name, value] of s3tcSRGBFormats) {
assert.strictEqual(s3tcSRGB[name], value, `${name} constant`);
assert(
srgbCompressedFormats.has(value),
`${name} should be listed in COMPRESSED_TEXTURE_FORMATS`);
}

const srgbTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, srgbTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
for (const [name, , byteLength] of s3tcSRGBFormats) {
gl.compressedTexImage2D(
gl.TEXTURE_2D, 0, s3tcSRGB[name], 4, 4, 0,
new Uint8Array(byteLength));
assertNoError(gl, `${name} compressedTexImage2D`);
}
gl.deleteTexture(srgbTexture);
assertNoError(gl, "WEBGL_compressed_texture_s3tc_srgb smoke");
}

function testExtensionCreationOptions() {
const defaultGl = createContext();
const defaultExtensions = defaultGl.getSupportedExtensions();
Expand Down Expand Up @@ -2735,6 +2822,7 @@ const gl = createContext();
console.log(gl.getParameter(gl.VERSION));
testRequiredWebGL2Methods(gl);
testSupportedExtensionsReflectGetExtension(gl);
testCompressedTextureS3TC(gl);
testExtensionCreationOptions();
testUnsupportedExtensionDoesNotWriteStderr();
testInfoLogEmptyStrings(gl);
Expand Down
Loading