Fix rendering bugs when device pixel ratio changes (#147)

Fixes #102
This commit is contained in:
Jamie Wong
2018-08-22 20:36:09 -07:00
committed by GitHub
parent 453f793042
commit f60ab630be
6 changed files with 64 additions and 31 deletions
+4
View File
@@ -1,5 +1,9 @@
## [Unreleased]
### Fixed
* Fixed rendering issues when switching between screens w/ different `devicePixelRatios` [#147]
## [0.7.1] - 2018-08-20
### Fixed
+1 -1
View File
@@ -49,7 +49,7 @@ export class CanvasContext {
}
private onBeforeFrame = () => {
this.animationFrameRequest = null
this.gl.setViewport(0, 0, this.gl.renderTargetWidth, this.gl.renderTargetHeight)
this.gl.setViewport(0, 0, this.gl.renderTargetWidthInPixels, this.gl.renderTargetHeightInPixels)
this.gl.clear(new Graphics.Color(1, 1, 1, 1))
for (const handler of this.beforeFrameHandlers) {
+21 -9
View File
@@ -141,11 +141,11 @@ export namespace Graphics {
abstract setRenderTarget(renderTarget: RenderTarget | null): void
abstract setViewport(x: number, y: number, width: number, height: number): void
abstract viewport: Rect
abstract width: number
abstract height: number
abstract widthInPixels: number
abstract heightInPixels: number
abstract renderTargetHeight: number
abstract renderTargetWidth: number
abstract renderTargetHeightInPixels: number
abstract renderTargetWidthInPixels: number
abstract setBlendState(source: BlendOperation, target: BlendOperation): void
setCopyBlendState() {
@@ -304,10 +304,10 @@ export namespace WebGL {
private _oldViewport = new Graphics.Rect()
private _width = 0
get width() {
get widthInPixels() {
return this._width
}
get height() {
get heightInPixels() {
return this._height
}
@@ -411,13 +411,13 @@ export namespace WebGL {
: this._defaultViewport
}
get renderTargetWidth() {
get renderTargetWidthInPixels() {
return this._currentRenderTarget != null
? this._currentRenderTarget.viewport.width
: this._width
}
get renderTargetHeight() {
get renderTargetHeightInPixels() {
return this._currentRenderTarget != null
? this._currentRenderTarget.viewport.height
: this._height
@@ -455,6 +455,18 @@ export namespace WebGL {
widthInAppUnits: number,
heightInAppUnits: number,
) {
const bounds = this._gl.canvas.getBoundingClientRect()
if (
this._width === widthInAppUnits &&
this._height === heightInPixels &&
bounds.width === widthInAppUnits &&
bounds.height === heightInAppUnits
) {
// Nothing to do here!
return
}
let canvas = this._gl.canvas
let style = canvas.style
canvas.width = widthInPixels
@@ -547,7 +559,7 @@ export namespace WebGL {
if (this._forceStateUpdate || !this._oldViewport.equals(viewport)) {
gl.viewport(
viewport.x,
this.renderTargetHeight - viewport.y - viewport.height,
this.renderTargetHeightInPixels - viewport.y - viewport.height,
viewport.width,
viewport.height,
)
+1 -1
View File
@@ -92,7 +92,7 @@ export class ViewportRectangleRenderer {
this.material.setUniformVec2('physicalOrigin', viewport.x, viewport.y)
this.material.setUniformVec2('physicalSize', viewport.width, viewport.height)
this.material.setUniformFloat('framebufferHeight', this.gl.renderTargetHeight)
this.material.setUniformFloat('framebufferHeight', this.gl.renderTargetHeightInPixels)
this.gl.setBlendState(
Graphics.BlendOperation.SOURCE_ALPHA,
+1
View File
@@ -43,6 +43,7 @@ export const ApplicationContainer = createContainer(
return {
activeProfileState,
dispatch,
canvasContext: state.glCanvas ? getCanvasContext(state.glCanvas) : null,
resizeCanvas: (
widthInPixels: number,
heightInPixels: number,
+36 -20
View File
@@ -12,6 +12,7 @@ import {StatelessComponent} from '../lib/typed-redux'
import {LeftHeavyFlamechartView, ChronoFlamechartView} from './flamechart-view-container'
import {SandwichViewState} from '../store/sandwich-view-state'
import {FlamechartViewState} from '../store/flamechart-view-state'
import {CanvasContext} from '../gl/canvas-context'
import {Graphics} from '../gl/graphics'
const importModule = import('../import')
@@ -169,7 +170,7 @@ export class Toolbar extends StatelessComponent<ToolbarProps> {
}
interface GLCanvasProps {
resizeCanvas: typeof Graphics.Context.prototype.resize
canvasContext: CanvasContext | null
setGLCanvas: (canvas: HTMLCanvasElement | null) => void
}
export class GLCanvas extends Component<GLCanvasProps, void> {
@@ -185,37 +186,52 @@ export class GLCanvas extends Component<GLCanvasProps, void> {
this.props.setGLCanvas(this.canvas)
}
private maybeResize() {
private maybeResize = () => {
if (!this.canvas) return
if (!this.props.canvasContext) return
let {width, height} = this.canvas.getBoundingClientRect()
width = Math.floor(width) * window.devicePixelRatio
height = Math.floor(height) * window.devicePixelRatio
// Still initializing: don't resize yet
if (width < 4 || height < 4) return
const oldWidth = this.canvas.width
const oldHeight = this.canvas.height
const widthInAppUnits = width
const heightInAppUnits = height
const widthInPixels = width * window.devicePixelRatio
const heightInPixels = height * window.devicePixelRatio
// Already at the right size
if (width === oldWidth && height === oldHeight) return
this.props.resizeCanvas(
width,
height,
width / window.devicePixelRatio,
height / window.devicePixelRatio,
this.props.canvasContext.gl.resize(
widthInPixels,
heightInPixels,
widthInAppUnits,
heightInAppUnits,
)
this.props.canvasContext.gl.clear(new Graphics.Color(1, 1, 1, 1))
}
onWindowResize = () => {
this.maybeResize()
if (this.props.canvasContext) {
this.props.canvasContext.requestFrame()
}
window.addEventListener('resize', this.onWindowResize)
}
componentWillReceiveProps(nextProps: GLCanvasProps) {
if (this.props.canvasContext !== nextProps.canvasContext) {
if (this.props.canvasContext) {
console.log('a')
this.props.canvasContext.removeBeforeFrameHandler(this.maybeResize)
}
if (nextProps.canvasContext) {
console.log('b')
nextProps.canvasContext.addBeforeFrameHandler(this.maybeResize)
nextProps.canvasContext.requestFrame()
}
}
}
componentDidMount() {
window.addEventListener('resize', this.onWindowResize)
requestAnimationFrame(() => this.maybeResize())
}
componentWillUnmount() {
if (this.props.canvasContext) {
this.props.canvasContext.removeBeforeFrameHandler(this.maybeResize)
}
window.removeEventListener('resize', this.onWindowResize)
}
render() {
@@ -232,7 +248,6 @@ export interface ActiveProfileState {
}
export type ApplicationProps = ApplicationState & {
resizeCanvas: typeof Graphics.Context.prototype.resize
setGLCanvas: (canvas: HTMLCanvasElement | null) => void
setLoading: (loading: boolean) => void
setError: (error: boolean) => void
@@ -242,6 +257,7 @@ export type ApplicationProps = ApplicationState & {
setFlattenRecursion: (flattenRecursion: boolean) => void
setProfileIndexToView: (profileIndex: number) => void
activeProfileState: ActiveProfileState | null
canvasContext: CanvasContext | null
}
export class Application extends StatelessComponent<ApplicationProps> {
@@ -615,7 +631,7 @@ export class Application extends StatelessComponent<ApplicationProps> {
onDragLeave={this.onDragLeave}
className={css(style.root, this.props.dragActive && style.dragTargetRoot)}
>
<GLCanvas setGLCanvas={this.props.setGLCanvas} resizeCanvas={this.props.resizeCanvas} />
<GLCanvas setGLCanvas={this.props.setGLCanvas} canvasContext={this.props.canvasContext} />
<Toolbar
saveFile={this.saveFile}
browseForFile={this.browseForFile}