OpenGL lwjgl-el kapcsolatos probléma, BufferedImage renderelés

OpenGL lwjgl-el kapcsolatos probléma, BufferedImage renderelés
2022-07-02T09:26:59+02:00
2022-07-02T18:22:22+02:00
2022-10-15T21:20:55+02:00
DFORCER
Problémám akadt mikor BufferedImaget szeretnék kirenderelni, az ablak fehér színű, és nem látszik rajta az aminek látszódnia kéne, a problémámra nem találtam eddig megoldást, vagy legalábbis lehet csak nem étettem meg a pontos problémát.

a kódrészletet csatolom.

Előre is köszönöm a segítséget!
Mutasd a teljes hozzászólást!
Csatolt állomány
Szóval ha a loop futása alatt akarok hozzáadni például egy négyzetet a képernyőhöz akkor ahoz egy külön szálon syncronized blokkban kell az imaget módosítani, majd egy join al megállítjuk az eventet és mikor bekerül a texturebe akkor folytatodjon a loop?

A joint nem tudom honnan vetted, de a szálak közti kommunikációnak több lehetséges módja lehet:

* synchronized blokk egy közös objektumon. Ekkor az írónak és az olvasónak is be kell mennie egy synchronized blokkba mielőtt hozzáfér a közös adatokhoz, de akármilyen adatszerkezetet használhatsz
* Konkurrens adattípusok használata, például a java.util.concurrent csomagból. Ezek akkor is helyesen működnek ha több szál fér hozzájuk synchronized blokk nélkül, de persze ettől még észben kell tartani hogy mi van ha hozzáférés közben más szál módosítja őket.
* volatile módosító használatával deklarált mező használata. Ezt könnyű elrontani, úgyhogy nem ajánlom ha nem érted pontosan hogyan működik.

Ha tegeződhetünk, te melyik megoldást látnádjónak?

Ha a végső kódban is csak téglalapok lesznek, akkor én elengedném a BufferedImage-et. Az OpenGL teljesen jól tud rajzolni egyszínű téglalapot magától is, csak bonyolítod a dolgokat ha textúrába rajzolod a téglalapokat, aztán egy darab textúrázott téglalapot raksz ki. Például lehet egy ConcurrentSkipListSet példányod, amibe berakod a kirajzolandó téglalapok adatait. Az event loop-ban a GL szál ezen mindig végigmenne és kirajzolná az aktuális állás szerint a dolgokat. Tetszőleges másik szál pedig tudna hozzáadni vagy elvenni elemeket úgy, hogy a következő képkocka már az új állapotot tükrözné. Érdemes utánanézni azoknak a GL hívásoknak, amik tömbökből dolgoznak, mert mondjuk ha százezer téglalapod van, nem mindegy hogy százezer GL hívás overhead-jét kell hozzá kifizetned vagy csak egy hívásét.

Ha a végső kódban valami bonyolultabbat kell kirajzolni, akkor lehetne egy ArrayBlockingQueue, amibe rajzoló parancsokat pakolsz. Aki változtatni akar a képen, az berak a queue-ba egy parancsot. Az event loopban a rajzolás előtt kipakolod a várakozó parancsokat, és a BufferedImage-edet módosítod, mielőtt a rajzolási parancsokat kiadod.

Én egyébként megpróbálnám lemérni, hogy tényleg ott van-e a lassulás ahol te gondolod. Modern oprendszereken a 2D-s műveleteket is gyorsítja a videokártya, szóval elvileg egy fix bitképnek nem kéne gyorsabban kirajzolódnia OpenGL-lel, mintha simán egy ablakon belül lenne. Ellenben ha a BufferedImage-re setRGB() hívásokkal rajzolsz téglalapokat, az magában is elég nagy lassulás lehet, hiszen annyi hívásod lesz ahány pixelből áll a téglalap.
Mutasd a teljes hozzászólást!

  • Szerintem soha nem adod át az OpenGL-nek hogy mit is szeretnél a textúrán látni. A glTexImage2D-t egyedül a compile() függvényből hívod. A compile()-t egyedül az addRect()-ből hívod. Az addRect()-et nem hívja senki.

    (Egyébként ez a pixelenkénti puffer feltöltés se túl hatékony, de elsőnek koncentrálj arra hogy menjen egyáltalán, azután is ráér az optimalizáció.)
    Mutasd a teljes hozzászólást!
  • Mert csak kivágtam a kódom, az addRect függvény meg van hívva egy párszor, csak nem találtam fontosanak a többi kódot is belerakni, mert az egy 1000soros kód, aminek az eredéményeiből jön ki hogy melyik pixel milyen színű legyen, és openGL el akartam felgyorsítani, már a JFramen való kirenderelés se volt nagyon lassú, de azért biztosabbnak érzem hogy a CPUrol levegyek egy kis terhet
    Mutasd a teljes hozzászólást!
  • Ilyen esetben érdemes egy minimális reprodukálható példát csatolnod a kérdésedhez, a válaszadás megkönnyítése végett (is). A válaszadók nem látnak a fejedbe, és ha csak úgy kimásolgatod a szerinted lényeges dolgokat, lehet hogy pont kimarad a hibát okozó kódrészlet. Másrészről a válasz is könnyebben születik, ha nem kell hozzá a nem releváns kódon átrágnia magát a segítőnek.
    Mutasd a teljes hozzászólást!
  • Itt egy példa aminek működnie kéne, de valamiért mégsem megy..:(
    A lényeg hogy téglalapokat rajzolnék ki a képernyőre. Lehet lenne jobb megoldás a BufferedImage-nél, csak én már megszoktam a jó öreg BufferedImaget, és openGL-ben nem vagyok valami tapasztalt.
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Ez a kód az OpenGLWindow konstruktorán belül szépen futtat neked egy event loop-ot, majd amikor az a loop már vígan véget ért, még hív egy addRect() metódust a window objektumodra. (Mellesleg az az addRect() a GL kontextus felszabadítása után próbál meg GL API-t hívni, ami bizonyára valamilyen hibával el fog szállni.)

    El kéne dönteni hogy akkor milyen működést szeretnél. Először hozza létre a kliens az ablakot, aztán állítgasson rajta, és a végén hagyja futni? Ha ez a cél, akkor nem a konstruktorban kéne futtatni az event loop-ot, hanem hagyni hogy a példányosító kód hívja meg, ha végzett a beállításokkal. Vagy ha a cél az, hogy fusson neked egy event loop, miközben valami más változtatgatja a megjelenített képet, akkor az már többszálas program lesz, a vele járó extra komplexitással.
    Mutasd a teljes hozzászólást!
  • Szóval ha a loop futása alatt akarok hozzáadni például egy négyzetet a képernyőhöz akkor ahoz egy külön szálon syncronized blokkban kell az imaget módosítani, majd egy join al megállítjuk az eventet és mikor bekerül a texturebe akkor folytatodjon a loop?

    Mert ahogy tudom lehetne vertex bufferek/indexekkel is hozzáadni négyzeteket, de ez nem tudom mennyivel növelné a komplexitását a kódnak, illetve ennek leimplementálásában se vagyok biztos, mivel egy négyzetet sikerül kirajzolnom a képernyőre mindenféle bufferekkel, de az hogy ha egy másikat négyzetet is ki akarok rajzolni azt hogyan kössem össze az eddigi bufferekkel azt nem tudom?.

    Ha tegeződhetünk, te melyik megoldást látnádjónak? vagy hogyan lehetne ezt leimplementáli úgy hogy ne kelljen azért egy hónapot rááldozni ahoz hogy az openGL-t alaposan megértsem?, mert ennek a projektnek nem az openGL megtanulása a lényege, hanem csak fel akarom gyoesnitani a programom hogy a gpu levegyen egy kis terhet a cpu-rol, előre is köszi a választ
    Mutasd a teljes hozzászólást!
  • Szóval ha a loop futása alatt akarok hozzáadni például egy négyzetet a képernyőhöz akkor ahoz egy külön szálon syncronized blokkban kell az imaget módosítani, majd egy join al megállítjuk az eventet és mikor bekerül a texturebe akkor folytatodjon a loop?

    A joint nem tudom honnan vetted, de a szálak közti kommunikációnak több lehetséges módja lehet:

    * synchronized blokk egy közös objektumon. Ekkor az írónak és az olvasónak is be kell mennie egy synchronized blokkba mielőtt hozzáfér a közös adatokhoz, de akármilyen adatszerkezetet használhatsz
    * Konkurrens adattípusok használata, például a java.util.concurrent csomagból. Ezek akkor is helyesen működnek ha több szál fér hozzájuk synchronized blokk nélkül, de persze ettől még észben kell tartani hogy mi van ha hozzáférés közben más szál módosítja őket.
    * volatile módosító használatával deklarált mező használata. Ezt könnyű elrontani, úgyhogy nem ajánlom ha nem érted pontosan hogyan működik.

    Ha tegeződhetünk, te melyik megoldást látnádjónak?

    Ha a végső kódban is csak téglalapok lesznek, akkor én elengedném a BufferedImage-et. Az OpenGL teljesen jól tud rajzolni egyszínű téglalapot magától is, csak bonyolítod a dolgokat ha textúrába rajzolod a téglalapokat, aztán egy darab textúrázott téglalapot raksz ki. Például lehet egy ConcurrentSkipListSet példányod, amibe berakod a kirajzolandó téglalapok adatait. Az event loop-ban a GL szál ezen mindig végigmenne és kirajzolná az aktuális állás szerint a dolgokat. Tetszőleges másik szál pedig tudna hozzáadni vagy elvenni elemeket úgy, hogy a következő képkocka már az új állapotot tükrözné. Érdemes utánanézni azoknak a GL hívásoknak, amik tömbökből dolgoznak, mert mondjuk ha százezer téglalapod van, nem mindegy hogy százezer GL hívás overhead-jét kell hozzá kifizetned vagy csak egy hívásét.

    Ha a végső kódban valami bonyolultabbat kell kirajzolni, akkor lehetne egy ArrayBlockingQueue, amibe rajzoló parancsokat pakolsz. Aki változtatni akar a képen, az berak a queue-ba egy parancsot. Az event loopban a rajzolás előtt kipakolod a várakozó parancsokat, és a BufferedImage-edet módosítod, mielőtt a rajzolási parancsokat kiadod.

    Én egyébként megpróbálnám lemérni, hogy tényleg ott van-e a lassulás ahol te gondolod. Modern oprendszereken a 2D-s műveleteket is gyorsítja a videokártya, szóval elvileg egy fix bitképnek nem kéne gyorsabban kirajzolódnia OpenGL-lel, mintha simán egy ablakon belül lenne. Ellenben ha a BufferedImage-re setRGB() hívásokkal rajzolsz téglalapokat, az magában is elég nagy lassulás lehet, hiszen annyi hívásod lesz ahány pixelből áll a téglalap.
    Mutasd a teljes hozzászólást!
  • Köszönöm ezt a sok tanácsot, a concurent csomagot még egyszer sem probálgattam, de ezekszerint eléggé érdemes ezeket az adat strukturákat is át tanulmányozni.

    Köszi mégegyszer, hogy időd fordítottál erre a "buta" problémára, de most is tanultam már jópár új dolgot amik segítségével lehet a régi projekteim újraalkotása is jobban sekerülne.

    Egyenlőre a projektembe csak egyszerű téglalapok kirenderelése a cél, de lehet késöbb kicsit komplexebb formákat is ki kell rajzolnom, egyébként egy a projekt egy saját java absztakció, programozási nyelvnek a grafikus funkcióihoz kellenének, bár ha már alapbol javara épül a nyelv, az nem lehet valami hű de gyors, de nem is ez a lényege, hanem hogy saját nyelv, és ezzel a nyelvel alossak egy két dolgot...

    Ha esetleg érdekel milyen projekt is ez, a Facebook oldalamon(Domonkos Gyömörey) lehet látni egy-két példát/leírást róla
    Mutasd a teljes hozzászólást!
  • bár ha már alapbol javara épül a nyelv, az nem lehet valami hű de gyors

    Szerintem ne írd le ilyen könnyen a nyelvet. Ez már nem az az interpretált bájtkód, ami a kezdetekben volt, a modern JVM-ek nagyon sok okosságot tudnak kezdeni a sokat futó kódokkal. Nem mondom hogy olyan gyors lesz mint a natív kód (bár ilyen benchmarkok is születtek specifikus esetekre), de nem is lesz nagyságrenddel lassabb. Amire figyelni kell hogy "be kell melegednie" a JVM-nek, szóval a rövid ideig futó programokra nem ideális, legalább is ha a teljesítmény fontos.
    Mutasd a teljes hozzászólást!
  • Hát igen, nem véletlen a legkedveltebb programnyelvem a java még a mai napig, hiába sokan utálják szerintem is nagyon jól meg állja ma is a helyét, főleg az enterprise alkalmazások terén.

    Annyira nem ismerem még a modernebb java verziókban az esetleg hatékonyabb adatstruktútákat, vagy metódusokat, így is van jó sok minden tanulni való a javan belül, mert hát sok minden érdekel az igazat megvalva
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd