Skip to content

Commit 1b7016a

Browse files
committed
Update framebuffer bindings logic.
This patch adds tracking for separate read/draw framebuffer bindings, which is a new feature in WebGL 2.0 and is needed for APIs like BlitFramebuffer. It also adds support for framebufferTextureLayer, another API used in WebGL 2.0.
1 parent ae673f0 commit 1b7016a

File tree

4 files changed

+53
-196
lines changed

4 files changed

+53
-196
lines changed

src/javascript/extensions/webgl-draw-buffers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class WebGLDrawBuffers {
5252
this._buffersState = buffers
5353
ctx.drawBuffersWEBGL([this.COLOR_ATTACHMENT0_WEBGL])
5454
return
55-
} else if (!ctx._activeFramebuffer) {
55+
} else if (!ctx._activeFramebuffers.draw) {
5656
if (buffers.length > 1) {
5757
ctx.setError(gl.INVALID_OPERATION)
5858
return

src/javascript/node-index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ function createContext (width, height, options) {
7171
ctx._renderbuffers = {}
7272

7373
ctx._activeProgram = null
74-
ctx._activeFramebuffer = null
74+
ctx._activeFramebuffers = { read: null, draw: null }
7575
ctx._activeRenderbuffer = null
7676
ctx._checkStencil = false
7777
ctx._stencilState = true

src/javascript/webgl-framebuffer.js

Lines changed: 0 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -10,106 +10,6 @@ class WebGLFramebuffer extends Linkable {
1010
this._width = 0
1111
this._height = 0
1212
this._status = null
13-
14-
this._attachments = {}
15-
this._attachments[gl.COLOR_ATTACHMENT0] = null
16-
this._attachments[gl.DEPTH_ATTACHMENT] = null
17-
this._attachments[gl.STENCIL_ATTACHMENT] = null
18-
this._attachments[gl.DEPTH_STENCIL_ATTACHMENT] = null
19-
20-
this._attachmentLevel = {}
21-
this._attachmentLevel[gl.COLOR_ATTACHMENT0] = 0
22-
this._attachmentLevel[gl.DEPTH_ATTACHMENT] = 0
23-
this._attachmentLevel[gl.STENCIL_ATTACHMENT] = 0
24-
this._attachmentLevel[gl.DEPTH_STENCIL_ATTACHMENT] = 0
25-
26-
this._attachmentFace = {}
27-
this._attachmentFace[gl.COLOR_ATTACHMENT0] = 0
28-
this._attachmentFace[gl.DEPTH_ATTACHMENT] = 0
29-
this._attachmentFace[gl.STENCIL_ATTACHMENT] = 0
30-
this._attachmentFace[gl.DEPTH_STENCIL_ATTACHMENT] = 0
31-
32-
if (ctx._extensions.webgl_draw_buffers) {
33-
const { webgl_draw_buffers: WebGLDrawBuffers } = ctx._extensions // eslint-disable-line
34-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT1_WEBGL] = null
35-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT2_WEBGL] = null
36-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT3_WEBGL] = null
37-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT4_WEBGL] = null
38-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT5_WEBGL] = null
39-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT6_WEBGL] = null
40-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT7_WEBGL] = null
41-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT8_WEBGL] = null
42-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT9_WEBGL] = null
43-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT10_WEBGL] = null
44-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT11_WEBGL] = null
45-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT12_WEBGL] = null
46-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT13_WEBGL] = null
47-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT14_WEBGL] = null
48-
this._attachments[WebGLDrawBuffers.COLOR_ATTACHMENT15_WEBGL] = null
49-
this._attachments[gl.NONE] = null
50-
this._attachments[gl.BACK] = null
51-
52-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT1_WEBGL] = 0
53-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT2_WEBGL] = 0
54-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT3_WEBGL] = 0
55-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT4_WEBGL] = 0
56-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT5_WEBGL] = 0
57-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT6_WEBGL] = 0
58-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT7_WEBGL] = 0
59-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT8_WEBGL] = 0
60-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT9_WEBGL] = 0
61-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT10_WEBGL] = 0
62-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT11_WEBGL] = 0
63-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT12_WEBGL] = 0
64-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT13_WEBGL] = 0
65-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT14_WEBGL] = 0
66-
this._attachmentLevel[WebGLDrawBuffers.COLOR_ATTACHMENT15_WEBGL] = 0
67-
this._attachmentLevel[gl.NONE] = null
68-
this._attachmentLevel[gl.BACK] = null
69-
70-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT1_WEBGL] = 0
71-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT2_WEBGL] = 0
72-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT3_WEBGL] = 0
73-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT4_WEBGL] = 0
74-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT5_WEBGL] = 0
75-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT6_WEBGL] = 0
76-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT7_WEBGL] = 0
77-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT8_WEBGL] = 0
78-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT9_WEBGL] = 0
79-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT10_WEBGL] = 0
80-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT11_WEBGL] = 0
81-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT12_WEBGL] = 0
82-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT13_WEBGL] = 0
83-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT14_WEBGL] = 0
84-
this._attachmentFace[WebGLDrawBuffers.COLOR_ATTACHMENT15_WEBGL] = 0
85-
this._attachmentFace[gl.NONE] = null
86-
this._attachmentFace[gl.BACK] = null
87-
}
88-
}
89-
90-
_clearAttachment (attachment) {
91-
const object = this._attachments[attachment]
92-
if (!object) {
93-
return
94-
}
95-
this._attachments[attachment] = null
96-
this._unlink(object)
97-
}
98-
99-
_setAttachment (object, attachment) {
100-
const prevObject = this._attachments[attachment]
101-
if (prevObject === object) {
102-
return
103-
}
104-
105-
this._clearAttachment(attachment)
106-
if (!object) {
107-
return
108-
}
109-
110-
this._attachments[attachment] = object
111-
112-
this._link(object)
11313
}
11414

11515
_performDelete () {

src/javascript/webgl-rendering-context.js

Lines changed: 51 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,14 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
262262
return null
263263
}
264264

265+
_getActiveFramebuffer (target) {
266+
if (target === this.READ_FRAMEBUFFER) {
267+
return this._activeFramebuffers.read
268+
} else {
269+
return this._activeFramebuffers.draw
270+
}
271+
}
272+
265273
_getAttachments () {
266274
return this._extensions.webgl_draw_buffers ? this._extensions.webgl_draw_buffers._ALL_ATTACHMENTS : DEFAULT_ATTACHMENTS
267275
}
@@ -305,7 +313,7 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
305313
}
306314

307315
_resizeDrawingBuffer (width, height) {
308-
const prevFramebuffer = this._activeFramebuffer
316+
const prevFramebuffer = this._activeFramebuffers.draw
309317
const prevTexture = this._getActiveTexture(this.TEXTURE_2D)
310318
const prevRenderbuffer = this._activeRenderbuffer
311319

@@ -402,24 +410,6 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
402410
}
403411
}
404412

405-
_tryDetachFramebuffer (framebuffer, renderbuffer) {
406-
// FIXME: Does the texture get unbound from *all* framebuffers, or just the
407-
// active FBO?
408-
if (framebuffer && framebuffer._linked(renderbuffer)) {
409-
const attachments = this._getAttachments()
410-
const framebufferAttachments = Object.keys(framebuffer._attachments)
411-
for (let i = 0; i < framebufferAttachments.length; ++i) {
412-
if (framebuffer._attachments[attachments[i]] === renderbuffer) {
413-
this.framebufferTexture2D(
414-
this.FRAMEBUFFER,
415-
attachments[i] | 0,
416-
this.TEXTURE_2D,
417-
null)
418-
}
419-
}
420-
}
421-
}
422-
423413
_validBlendFunc (factor) {
424414
return factor === this.ZERO ||
425415
factor === this.ONE ||
@@ -591,18 +581,14 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
591581
} else {
592582
return
593583
}
594-
const activeFramebuffer = this._activeFramebuffer
595-
if (activeFramebuffer !== framebuffer) {
596-
if (activeFramebuffer) {
597-
activeFramebuffer._refCount -= 1
598-
activeFramebuffer._checkDelete()
599-
}
600-
if (framebuffer) {
601-
framebuffer._refCount += 1
602-
}
603-
}
604-
if (error === 0) {
605-
this._activeFramebuffer = framebuffer
584+
585+
if (target === this.FRAMEBUFFER) {
586+
this._activeFramebuffers.draw = framebuffer
587+
this._activeFramebuffers.read = framebuffer
588+
} else if (target === this.READ_FRAMEBUFFER) {
589+
this._activeFramebuffers.read = framebuffer
590+
} else if (target === this.DRAW_FRAMEBUFFER) {
591+
this._activeFramebuffers.draw = framebuffer
606592
}
607593
}
608594

@@ -1239,8 +1225,14 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
12391225
return
12401226
}
12411227

1242-
if (this._activeFramebuffer === framebuffer) {
1228+
if (this._activeFramebuffers.draw === framebuffer && this._activeFramebuffers.read === framebuffer) {
12431229
this.bindFramebuffer(this.FRAMEBUFFER, null)
1230+
} else if (this._isWebGL2()) {
1231+
if (this._activeFramebuffers.read === framebuffer) {
1232+
this.bindFramebuffer(this.READ_FRAMEBUFFER, null)
1233+
} else if (this._activeFramebuffers.draw === framebuffer) {
1234+
this.bindFramebuffer(this.DRAW_FRAMEBUFFER, null)
1235+
}
12441236
}
12451237

12461238
framebuffer._pendingDelete = true
@@ -1273,10 +1265,6 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
12731265
this.bindRenderbuffer(this.RENDERBUFFER, null)
12741266
}
12751267

1276-
const activeFramebuffer = this._activeFramebuffer
1277-
1278-
this._tryDetachFramebuffer(activeFramebuffer, renderbuffer)
1279-
12801268
renderbuffer._pendingDelete = true
12811269
renderbuffer._checkDelete()
12821270
}
@@ -1316,28 +1304,6 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
13161304
}
13171305
this.activeTexture(this.TEXTURE0 + curActive)
13181306

1319-
// FIXME: Does the texture get unbound from *all* framebuffers, or just the
1320-
// active FBO?
1321-
const ctx = this
1322-
const activeFramebuffer = this._activeFramebuffer
1323-
function tryDetach (framebuffer) {
1324-
if (framebuffer && framebuffer._linked(texture)) {
1325-
const attachments = ctx._getAttachments()
1326-
for (let i = 0; i < attachments.length; ++i) {
1327-
const attachment = attachments[i]
1328-
if (framebuffer._attachments[attachment] === texture) {
1329-
ctx.framebufferTexture2D(
1330-
this.FRAMEBUFFER,
1331-
attachment,
1332-
this.TEXTURE_2D,
1333-
null)
1334-
}
1335-
}
1336-
}
1337-
}
1338-
1339-
tryDetach(activeFramebuffer)
1340-
13411307
// Mark texture for deletion
13421308
texture._pendingDelete = true
13431309
texture._checkDelete()
@@ -1493,14 +1459,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
14931459
throw new TypeError('framebufferRenderbuffer(GLenum, GLenum, GLenum, WebGLRenderbuffer)')
14941460
}
14951461

1496-
if (!this._validFramebufferAttachment(attachment) ||
1497-
renderbufferTarget !== this.RENDERBUFFER) {
1498-
this.setError(this.INVALID_ENUM)
1499-
return
1500-
}
1501-
1502-
const framebuffer = this._activeFramebuffer
1503-
if (!framebuffer) {
1462+
// Since we emulate the default framebuffer, we can't rely on ANGLE's validation.
1463+
if (!this._getActiveFramebuffer(target)) {
15041464
this.setError(this.INVALID_OPERATION)
15051465
return
15061466
}
@@ -1526,46 +1486,41 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
15261486
throw new TypeError('framebufferTexture2D(GLenum, GLenum, GLenum, WebGLTexture, GLint)')
15271487
}
15281488

1529-
// Check parameters are ok
1530-
if (!this._validFramebufferAttachment(attachment)) {
1531-
this.setError(this.INVALID_ENUM)
1489+
// Check object ownership
1490+
if (texture && !this._checkWrapper(texture, WebGLTexture)) {
15321491
return
15331492
}
15341493

1535-
if (level !== 0) {
1536-
this.setError(this.INVALID_VALUE)
1494+
// Since we emulate the default framebuffer, we can't rely on ANGLE's validation.
1495+
if (!this._getActiveFramebuffer(target)) {
1496+
this.setError(this.INVALID_OPERATION)
15371497
return
15381498
}
15391499

1540-
// Check object ownership
1541-
if (texture && !this._checkWrapper(texture, WebGLTexture)) {
1542-
return
1500+
super.framebufferTexture2D(target, attachment, textarget, texture?._ ?? null, level)
1501+
}
1502+
1503+
framebufferTextureLayer (target, attachment, texture, level, layer) {
1504+
target |= 0
1505+
attachment |= 0
1506+
level |= 0
1507+
layer |= 0
1508+
if (!checkObject(texture)) {
1509+
throw new TypeError('framebufferTextureLayer(GLenum, GLenum, WebGLTexture, GLint, GLint)')
15431510
}
15441511

1545-
// Check texture target is ok
1546-
if (textarget === this.TEXTURE_2D) {
1547-
if (texture && texture._binding !== this.TEXTURE_2D) {
1548-
this.setError(this.INVALID_OPERATION)
1549-
return
1550-
}
1551-
} else if (this._validCubeTarget(textarget)) {
1552-
if (texture && texture._binding !== this.TEXTURE_CUBE_MAP) {
1553-
this.setError(this.INVALID_OPERATION)
1554-
return
1555-
}
1556-
} else {
1557-
this.setError(this.INVALID_ENUM)
1512+
// Check object ownership
1513+
if (texture && !this._checkWrapper(texture, WebGLTexture)) {
15581514
return
15591515
}
15601516

1561-
// Check a framebuffer is actually bound
1562-
const framebuffer = this._activeFramebuffer
1563-
if (!framebuffer) {
1517+
// Since we emulate the default framebuffer, we can't rely on ANGLE's validation.
1518+
if (!this._getActiveFramebuffer(target)) {
15641519
this.setError(this.INVALID_OPERATION)
15651520
return
15661521
}
15671522

1568-
super.framebufferTexture2D(target, attachment, textarget, texture?._ ?? null, level)
1523+
super.framebufferTextureLayer(target, attachment, texture?._ ?? null, level, layer)
15691524
}
15701525

15711526
frontFace (mode) {
@@ -1651,7 +1606,9 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
16511606
case this.CURRENT_PROGRAM:
16521607
return this._activeProgram
16531608
case this.FRAMEBUFFER_BINDING:
1654-
return this._activeFramebuffer
1609+
return this._activeFramebuffers.draw
1610+
case this.READ_FRAMEBUFFER_BINDING:
1611+
return this._activeFramebuffers.read
16551612
case this.RENDERBUFFER_BINDING:
16561613
return this._activeRenderbuffer
16571614
case this.TEXTURE_BINDING_2D:
@@ -1731,8 +1688,8 @@ class WebGLRenderingContextHelper extends NativeWebGLRenderingContext {
17311688
attachment |= 0
17321689
pname |= 0
17331690

1734-
// Note: there's an ANGLE bug where it doesn't check for the default framebuffer in WebGL compat.
1735-
if (!this._activeFramebuffer) {
1691+
// Since we emulate the default framebuffer, we can't rely on ANGLE's validation.
1692+
if (!this._getActiveFramebuffer(target)) {
17361693
this.setError(this.INVALID_OPERATION)
17371694
return null
17381695
}

0 commit comments

Comments
 (0)