Specy Posted April 21, 2021 Share Posted April 21, 2021 Hey, i'm making a music composer for a webapp, i'm using react-pixi to render all the information that i need for the song, they are basically made out of columns with inside of it the single notes, in total there are 3 different elements that are rendered, the only thing that changes are their position, i'm already using culling to not render elements which aren't visible, but when there are many notes on screen, it still lags, i've found the issue being the repetitive drawing of the notes. What i want to ask is, is there a way to speed up the drawing of elements on screen by caching the elements to render ? will this help performance wise? worst case scenario i render 40 columns and 840 notes every +-50ms I attached a video to show the issue i'm having now (WATCHOUT EARRAPE) Screen-capture - 2021-04-21t105556.314-1.mp4 Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted April 21, 2021 Share Posted April 21, 2021 > What i want to ask is, is there a way to speed up the drawing of elements on screen by caching the elements to render it wont help. The number of elements that are bounded to react, and number of elements that are managed to pixi are your problems. As always with "100k bunnies" tasks - you have to realize that algorithm is divided by two parts. 1. high-level algo: write the algo that fills up all notes in current screen, maybe a bit bigger than current screen. Its your controlling algo, it updates your notes, not react! 2. low-level algo: choose something more effective than Container/Sprite combination. Put many elements in same Graphics or @pixi/tilemap , manage multiple elemetns like that, for example. If I had more time I could help and post more information, but in this case - im sorry, you have to post more details and maybe source code Quote Link to comment Share on other sites More sharing options...
Specy Posted April 21, 2021 Author Share Posted April 21, 2021 (edited) Ok wait let me first track down where the issue is then i'll share the rest Edited April 21, 2021 by Specy Quote Link to comment Share on other sites More sharing options...
Specy Posted April 21, 2021 Author Share Posted April 21, 2021 <Stage width={s.width} height={s.height} options={pixiOptions} > <Container anchor={[0.5, 0.5]} x={xPos} > {data.columns.map((column, i) => { if (counter > 15) { switcher = !switcher counter = 0 } counter++ if (!isVisible(i, data.selected)) return null let standardBg = columnBackgrounds[Number(switcher)] let bgColor = column.tempoDivider === 1 ? standardBg : column.color return <Column key={i} data={column} index={i} sizes={sizes} bgColor={bgColor} click={functions.selectColumn} isSelected={i === data.selected} /> })} </Container> </Stage> Here's the code that renders the elements, the issue seems to be with the <Column> element, with the profiler i saw that the issue seems to be with react, in fact if i return an empty <Container> it still lags as much as it did if i actually rendered the column component, if i return null, the lag disappears. I guess i have to do a more "low level" approach Quote Link to comment Share on other sites More sharing options...
Specy Posted April 21, 2021 Author Share Posted April 21, 2021 function Column(props) { let { data, index, sizes, click, isSelected, bgColor } = props let color = isSelected ? selectedColor : bgColor function drawBg(g) { g.clear() g.beginFill(color, 1) g.drawRect(0, 0, sizes.width, sizes.height) g.lineStyle(1, 0x00000, 0.8) g.moveTo(sizes.width, 0) g.lineTo(sizes.width, sizes.height) g.moveTo(0, 0) g.lineTo(0, sizes.height) } let noteHeight = sizes.height / 21 - (noteMargin * 2) let noteWidth = sizes.width - (noteMargin * 2) function drawNote(g, note) { g.clear() g.beginFill(note.color, 1) g.drawRoundedRect(noteMargin, positions[note.index] * sizes.height / 21, noteWidth, noteHeight, noteBorder) g.endFill() } //index color return <Container pointerdown={() => click(index)} interactive={true} x={sizes.width * index} > <Graphics draw={drawBg} /> {data.notes.map((note) => { return <Graphics draw={(g) => drawNote(g, note)} /> })} </Container> } Ok this is the code that renders the column, the lag coming from an empty <Column> that i explained before seems to not be that influenctial, the biggest performance hit is that <Graphics draw={(g) => drawNote(g, note)} />, if i return null there, the lag is greately reduced, maybe instead of making a new <Graphics> component for each note i could just draw everything in <Graphics draw={drawBg}/> component Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted April 21, 2021 Share Posted April 21, 2021 OK , now I agree that its definitely a case for caching textures. Just draw individual notes with photoshop on one atlas, and use sprites. Quote Link to comment Share on other sites More sharing options...
Specy Posted April 21, 2021 Author Share Posted April 21, 2021 i need to have the element sizes dynamic and customizable so i prefer to do the textures with the code, is there a way i can render something once and then reuse them inside sprites in the code? Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted April 21, 2021 Share Posted April 21, 2021 yes, look at renderTexture 's . Also if you want better quality, just draw those things on canvas2d and use "Texture.from(myCanvas)" and "texture.update()" every time you change that canvas. karlbot 1 Quote Link to comment Share on other sites More sharing options...
Specy Posted April 21, 2021 Author Share Posted April 21, 2021 ok i'll see what i can do, i just started out with pixi and graphics in general so everything is still unknown to me and i don't know how to behave, i'll first finish the functionality then move to optimization ivan.popelyshev 1 Quote Link to comment Share on other sites More sharing options...
Specy Posted April 22, 2021 Author Share Posted April 22, 2021 Ok so i'm having issues trying to generate the texture, i followed some code that i saw and it showed that this should work? but it doesn't, i get an error "sprite image prop is invalid", this is the code i use to generate the cache: the cached elements are RenderTexture import {TempoChangers} from "../SongUtils" import * as PIXI from "pixi.js" class ComposerCache{ constructor(width,height){ this.width = width this.height = height this.cache = { columns: [], notes: [] } this.app = new PIXI.Application({ width: width, height:height, }) this.generate() } generate = () => { TempoChangers.forEach(tempoChanger => { let column = new PIXI.Graphics() column.clear() column.beginFill(tempoChanger.color, 1) column.drawRect(0, 0, this.width, this.height) column.lineStyle(1, 0x00000, 0.8) column.moveTo(this.width, 0) column.lineTo(this.width, this.height) column.moveTo(0, 0) column.lineTo(0, this.height) let b = this.app.renderer.generateTexture(column) this.cache.columns.push(b) }) } } And when i go to render it i just do: <Sprite image={cache.columns[data.tempoChanger]} > </Sprite> Quote Link to comment Share on other sites More sharing options...
Specy Posted April 22, 2021 Author Share Posted April 22, 2021 I tried like you said, so using canvas 2d, i then converted the canvas to dataURI and fed that into the sprite, performance is a bit better compared to before but it still lags a lot Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted April 22, 2021 Share Posted April 22, 2021 the idea is to generate all possible notes, and re-use those textures. Better if its actually one texture and you use regions of it "new PIXI.Texture(baseTexture, frame)" Quote Link to comment Share on other sites More sharing options...
Specy Posted April 22, 2021 Author Share Posted April 22, 2021 Just now, ivan.popelyshev said: the idea is to generate all possible notes, and re-use those textures. Better if its actually one texture and you use regions of it "new PIXI.Texture(baseTexture, frame)" that's what i did, i'm now reusing all textures and pre render them, i think it might be because of pixi library i'm using for react (@inlet/react-pixi) which watching benchmarks seems to be 4 times slower than normal pixi when using many elements Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted April 22, 2021 Share Posted April 22, 2021 (edited) Use SpectorJS chrome extension to see number of drawcalls in frame and whether your re-use of textures actually works. Also, you have to take profile of this app and see which JS functions are slow. Edited April 22, 2021 by ivan.popelyshev Quote Link to comment Share on other sites More sharing options...
Specy Posted April 22, 2021 Author Share Posted April 22, 2021 (edited) 16 minutes ago, ivan.popelyshev said: Also, you have to take profile of this app and see which JS functions are slow. That's really hard... with react it's all a mess, everything is super nested but the main issue seems to come from the changing of state and the rendering, they do a 50/50. I'll try to reduce the amounts of state changes but i don't think i can change much capture 21_20_32 (1).json Edited April 22, 2021 by Specy Quote Link to comment Share on other sites More sharing options...
jonforum Posted April 23, 2021 Share Posted April 23, 2021 (edited) just in case , if you using react , you have debugger tools thats help you to debugg your app. i hope you are not working without this !? It should help a lot. Also for pixijs! Another debugg tools avaible.https://chrome.google.com/webstore/detail/pixijs-devtools/aamddddknhcagpehecnhphigffljadon And also the native memory tool in devtool allow you check and compare all textures between 2 states. This can help. Edited April 23, 2021 by jonforum Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.