
ETC1圢åŒã¯ ãOpenGL ES 2.0ãæèŒãããã¹ãŠã®Androidããã€ã¹ã§ã®ãµããŒãã«å¿ é ã§ãããæ¶è²»ãããRAMãæé©åããããã®è¯ãåºçºç¹ã§ãã PNGãJPEGãWebP圢åŒãšæ¯èŒããŠãETC1ãã¯ã¹ãã£ã®èªã¿èŸŒã¿ã¯ãã¡ã¢ãªã®éåžžã®ã³ããŒã«ããéäžçãªèšç®ãªãã§å®è¡ãããŸãã äœéã¡ã¢ãªããé«éã¡ã¢ãªã«éä¿¡ããããã¯ã¹ãã£ããŒã¿ã®ãµã€ãºãå°ãããªããããã²ãŒã ã®ããã©ãŒãã³ã¹ãåäžããŸãã
OpenGL ES 3.0ãæèŒããããã€ã¹ã§ã¯ãETC1圢åŒã®ãã¯ã¹ãã£ã䜿çšã§ããŸããããã¯ãæ¹è¯ãããETC2圢åŒã®ãµãã»ããã§ã ã
ETC1圢åŒã§ã®å§çž®ãã¯ã¹ãã£ã®äœ¿çš
ETC1圢åŒã«ã¯RGBã«ã©ãŒã³ã³ããŒãã³ãã®ã¿ãå«ãŸããŠãããããã¢ã«ãã¡ãã¬ã³ãã£ã³ã°ãç¡å¹ã«ããŠãã€ã³ãããããšããå§ãããäžéæãªèæ¯ã«é©ããŠããŸãã
éæãªã°ã©ãã£ãã¯ã¹ãã©ãããŸããïŒ ãã®ããã«ã2ã€ã®ãã¯ã¹ãã£ETC1ïŒä»¥é-2xETC1ïŒã䜿çšããŸãã
-æåã®ãã¯ã¹ãã£ã«å ã®RGBãä¿åããŸãã
-2çªç®ã®ãã¯ã¹ãã£ã§ãå ã®ã¢ã«ãã¡ïŒä»¥é-AïŒãRGBã³ã³ããŒãã³ãã«ã³ããŒããŠä¿åããŸãã
次ã«ã2xETC1ãã¯ã»ã«ã·ã§ãŒããŒã§ã次ã®æ¹æ³ã§è²ã埩å ããŸãã
uniform sampler2D u_Sampler; uniform sampler2D u_SamplerAlpha; varying vec2 v_TexCoords; varying vec4 v_Color; void main() { vec4 sample = texture2D(u_Sampler, v_TexCoords); sample.a = texture2D(u_SamplerAlpha, v_TexCoords).r; gl_FragColor = sample * v_Color; }
ETC1圢åŒã«å§çž®ããåã«ã¢ãã©ã¹ãæºåããæ©èœ
ETC1圢åŒã¯ç¬ç«ãã4x4ãã¯ã»ã«ãããã¯ã䜿çšãããããç°ãªãèŠçŽ ãå ±éãããã¯ã«å ¥ããªãããã«ãã¢ãã©ã¹ã«é 眮ãããèŠçŽ ã®äœçœ®ã4ãã¯ã»ã«ã«æããããšããå§ãããŸãã
ã¢ãã©ã¹ã«é 眮ããããã¹ãŠã®èŠçŽ ã¯ã1ã2ãã¯ã»ã«ã®åãã®è¿œå ã®ä¿è·ãã¬ãŒã ãå¿ èŠãªã®ã§ãé¢ç©ããããã«å¢å ããŸãã ããã¯ãã¬ã³ããªã³ã°ã®åæ°åº§æšïŒã¹ãã©ã€ãã®æ»ãããªåãã«ããïŒãšãã¯ã¹ãã£ã®ãã€ãªãã¢ãã£ã«ã¿ãªã³ã°ã«ãããã®ã§ãã äœãèµ·ãã£ãŠããã®ããæ°åŠçã«æ£åœåããã«ã¯ãå¥ã®èšäºãå¿ èŠã§ãã
å€è§åœ¢ã®ã¢ãã©ã¹ã®å ŽåãèŠçŽ ã¯èš±å®¹å¯èœãªè·é¢ãŸã§é¢å©ããŸãã 4TC ETC1ãããã¯ã¯ãã¹ãŠã2x4ãŸãã¯4x2ã®ã¹ããªããã®ãã¢ã§æ§æãããŠããããã2ãã¯ã»ã«ã®è·é¢ã§ãè¯å¥œãªæç±å¹æãåŸãããŸãã
ETC1圢åŒã«å®æ§çã«å§çž®ã§ãããã®ã¯äœã§ããïŒ
ç¡æã®ãŠãŒãã£ãªãã£ã®äžããéžæã§ããŸãã
-ETC2Comp ;
-Mali GPUãã¯ã¹ãã£å§çž®ããŒã« ã
-PVRTexTool ;
-rg-etc1
é«å質ã®ã°ã©ãã£ãã¯å§çž®ãè¡ãã«ã¯ãç¥èŠã®ç¹æ§ãèæ ®ããç¥èŠææšãèšå®ããäœéã¢ãŒããšæé©ã¢ãŒããéžæããå¿ èŠããããŸãã ãã¯ã¹ãã£2048x2048ãå®æ§çã«å§çž®ããããšãããšãããã¯é·ãããã»ã¹ã§ããããšãããããŸã...ãããããå€ãã®éçºè ãäžé«éã®é«éãªä»£æ¿æ段ã«å¶éãããŠããçç±ã§ãã ãã£ãšè¯ãããããšã¯å¯èœã§ããïŒ
Playrixããã°ã©ããŒã®1人ã«ããç¬èªã®ãŠãŒãã£ãªãã£EtcCompressã®ãŒãããã®äœæã®è©±ã¯ãETC1圢åŒã®ã°ã©ãã£ãã¯ã¹ã®æçµçãªå§çž®ã蚪åäžã«3æéã®èšªåãè¶ ãã2014幎1æã«ããã®ãŒããŸãã
ETC1圢åŒã§ã®é«å質å§çž®ã®ã¢ã€ãã¢
ETC1圢åŒã¯ç¬ç«ãããããã¯åœ¢åŒã§ãã ãããã£ãŠãåã ã®ãããã¯ãå§çž®ããå€å žçãªã¢ãããŒãã䜿çšããŸãããããã¯ååã«äžŠååãããŠããŸãã ãã¡ããããããã¯ã®ã»ãããèæ ®ããããšã§ãããã¯ã®çµåãæ¹åããããšãã§ããŸããããã®å Žåãã¢ãã©ã¹èŠçŽ ã«å±ããããšã«é¢ããæ å ±ãå¿ èŠã«ãªããã¿ã¹ã¯ã®èšç®ã®è€éããæ¥æ¿ã«å¢å ããŸãã
dssimãŠãŒãã£ãªãã£ã¯ãå§çž®çµæã®æ¯èŒã«é©ããŠããŸãã
-2ã€ã®2x4ã¹ããªããïŒããããç¬èªã®åºæ¬çãª4ãããã«ã©ãŒãæã€ïŒã¯ãã³ãŒãã§CompressBlockColor44ïŒ...ã0ïŒãåŒã³åºããŸãã
-ã³ãŒãã§CompressBlockColor44ïŒ...ã1ïŒãåŒã³åºã2ã€ã®4x2ã¹ããªããããããããç¬èªã®åºæ¬çãª4ãããã«ã©ãŒãæã¡ãŸãã
-2ã€ã®2x4ã¹ããªãããæåã®ã³ãŒãã¯åºæ¬çãª5ãããè²ã2çªç®ã®ã³ãŒãã¯CompressBlockColor53ïŒ...ã2ïŒãåŒã³åºãã³ãŒãã§3ãããã®ç¯å²ã®æåã®ã³ãŒããšã¯åºæ¬è²ãç°ãªããŸãã
-2ã€ã®4x2ã¹ããªãããæåã¯åºæ¬çãª5ãããè²ã2çªç®ã¯3ãããç¯å²ã®æåãšåºæ¬è²ãç°ãªãã³ãŒãã§ãCompressBlockColor53ïŒ...ã3ïŒãåŒã³åºããŸãã
![]() | ![]() | ![]() | ![]() |
2x4ã444 + 444 | 4x2ã444 + 444 | 2x4ã555 + 333 | 4x2ã555 + 333 |
PixelError = 0.715158 * (dstG - srcG)^2 + 0.212656 * (dstR - srcR)^2 + 0.072186 * (dstB - srcB)^2
ä¿æ°ã«1000ãæããŠäžžããããšã«ãããæŽæ°å€ã«ãªããŸãã 4x4ãããã¯ã®åæãšã©ãŒã¯
kUnknownError = (255^2) * 1000 * 16 + 1
ã«ãªããŸã
255
ã¯è²æåã®æ倧ãšã©ãŒã
1000
ã¯éã¿ã®åºå®åèšã16ã¯ãã¯ã»ã«æ°ã§ãã ãã®ãããªãšã©ãŒã¯
int32_t
é©åããŸãã æŽæ°ã®2ä¹ã¯ã ã¬ã³ã2.2ãèæ ®ããããšã«æå³ãè¿ãããšã«æ°ä»ããããããŸããã
PSNRã«ã¯åŒ±ç¹ããããŸãã ããšãã°ããã¬ãã
c1 = c0 - d
ããã³
c2 = c0 + d
ããéžæããŠè²
c0
å¡ãã€ã¶ããã³ãŒãã£ã³ã°ãããšãåããšã©ãŒ
d^2
çºçããŸãã ããã¯ãããããçš®é¡ã®ãã§ãã«ãŒã䌎ã
c1
ãš
c2
éã®ã©ã³ãã ãªéžæãæå³ããŸãã
çµæãæ¹åããããã«ããããã¯å ã®æçµèšç®ãSSIMã«ãã£ãŠå®è¡ãããŸãã ã³ãŒãã§ã¯ãããã¯ãSSIM_INITãSSIM_UPDATEãSSIM_CLOSEãSSIM_OTHERãSSIM_FINALã®ãã¯ãã䜿çšããŠãComputeTableColoré¢æ°ã§å®è¡ãããŸãã èãã¯ãæé«ã®PSNRïŒèŠã€ãã£ããšã³ã³ãŒãã¢ãŒãïŒãæã€ãã¹ãŠã®ãœãªã¥ãŒã·ã§ã³ã«å¯ŸããŠãæé«ã®SSIMãæã€ãœãªã¥ãŒã·ã§ã³ãéžæããããšããããšã§ãã
GuessColor4é¢æ°ã¯ãåå·®ãšããŒã¹ã«ã©ãŒã³ã³ããŒãã³ããå埩åŠçããŸãã
for (int q = 0; q < 8; q++) for (int c0 = 0; c0 < c0_count; c0++) // G, c0_count <= 16 for (int c1 = 0; c1 < c1_count; c1++) // R, c1_count <= 16 for (int c2 = 0; c2 < c2_count; c2++) // B, c2_count <= 16 ComputeErrorGRB(c, q);
äŸåããããŒã¹ã«ã©ãŒã®å Žåãã¹ããªãããµã€ã¯ã«ãäºéã«ãã¹ãããããããã¢ã«ãŽãªãºã ã®è€éããå¢ããŸãã CompressBlockColor53é¢æ°ã¯ãåå·®ãåæããŸãã
for (int qa = 0; qa < 8; qa++) for (int qb = 0; qb < 8; qb++) AdjustColors53(qa, qb);
AdjustColors53é¢æ°ã¯ã2ã€ã®åºæ¬è²ã®ã³ã³ããŒãã³ããåæããŸãã
for (int a0 = 0; a0 < a0_count; a0++) // G, a0_count <= 32 for (int a1 = 0; a1 < a1_count; a1++) // R, a1_count <= 32 for (int a2 = 0; a2 < a2_count; a2++) // B, a2_count <= 32 ComputeErrorGRB(a, qa); for (int d0 = Ld0; d0 <= Hd0; d0++) // G, d0_count <= 8 for (int d1 = Ld1; d1 <= Hd1; d1++) // R, d1_count <= 8 for (int d2 = Ld2; d2 <= Hd2; d2++) // B, d2_count <= 8 b = a + d; ComputeErrorGRB(b, qb);
æ瀺ããã培åºçãªæ€çŽ¢ã¯ãåæ§ã®ãŠãŒãã£ãªãã£ã®æé«ã®å§çž®ã¢ãŒããããé«éã§ã¯ãããŸããããããã¯åŸ¹åºçãªæ€çŽ¢ã§ãããããã«é«éåãããŸãã

éèŠã§ã¯ãªããã¯ã»ã«ã¯ç¡èŠã§ããŸãããã®ãããæåã¯FilterPixelsColorã®åŒã³åºãã§ããã³ãŒãã§ãã£ã«ã¿ãªã³ã°ããŸãã äžæ¹ããã¹ãŠã®éæãã¯ã»ã«ãéèŠãšããããã§ã¯ãããŸãããå°ãªããšã1ã2ãã¯ã»ã«ã®ä¿è·ãã¬ãŒã ãšå¢çãçœãããå¹æãæãåºããŠãã ãã ã
ãããã£ãŠãã¹ãã³ã·ã«ãäœæããŸãããã®å ŽåããŒãã¯éèŠã§ãªããã¯ã»ã«ãæå³ããæ£ã®å€ã¯éèŠãªãã¯ã»ã«ã瀺ããŸãã ã¹ãã³ã·ã«ã¯ãOutlineAlphaé¢æ°ã§ããã³ãŒãã«ã¹ãããŒã¯ïŒéåžžã¯1ãã¯ã»ã«ãŸãã¯2ãã¯ã»ã«ã®ãµã€ãºïŒãé©çšããããšã«ããããã£ãã«Aã«åºã¥ããŠäœæãããŸãã
å®è·µã瀺ããŠããããã«ãã¹ãã³ã·ã«ã䜿çšãããšããªããžã§ã¯ãã®å§çž®ãããå¢çãæ¹åãããç®ã«èŠããªããããã¯ãããã«é©åã«ããã±ãŒãžåããããžãããã©ãã¯ã®è²ã«ãªããŸãã ãªã¹ãããããŠãŒãã£ãªãã£ãå«ãRGBãšAã®åå¥ã®å§çž®ãšæ¯èŒããŠãå質ã®é¡èãªåäžãããããã®ã¯ã¹ãã³ã·ã«ã®ã¢ã€ãã¢ã§ãã

ãããã£ãŠã2xETC1å§çž®ã¯ãEtcMainWithArgsé¢æ°ã«å®è£ ããã次ã®æé ã§è¡šãããšãã§ããŸãã
1ïŒãã£ãã«AãETC1圢åŒã«å§çž®ããŸãã
2ïŒå§çž®ããããã£ãã«Aã解åããŸãã
3ïŒå¯èŠã®ã¹ãããŒã¯ãäœæããŸãïŒA> 0ïŒãã¹ãã³ã·ã«ãååŸããŸãã
4ïŒã¹ãã³ã·ã«ãèæ ®ããŠãRGBãã£ã³ãã«ãETC1圢åŒã«å§çž®ããŸãã
ETC1圢åŒãžã®å質ã®å§çž®ãå éããããã®ã¢ã€ãã¢
ãŠãŒãã£ãªãã£ããã®çšéãèŠã€ããããã«ã¯ãçµæã®å質ã«å ããŠãåäœæéãéèŠã§ãã èæ ®ãããç¶²çŸ çãããã¯å§çž®ã¢ã«ãŽãªãºã ã¯ã貪欲ãªã¢ã«ãŽãªãºã ã«åºã¥ãããã®ãå«ããäœæ¥éçšã«ãããè¿ éãªåæãã¥ãŒãªã¹ãã£ãã¯æšå®ããã³æçšãªã«ãããªãã«å€ããŸãã
ãã®å Žåãããã«ãŒã¯åºåãã¡ã€ã«ãèªã¿åã£ãŠè§£åããæ¢åã®ãšã©ãŒãèšç®ããããšããŠããŸãããããæåã®è§£æ±ºçã«ãªããŸãã ãã¡ã€ã«ãååšããªãå ŽåããŒãã®åæ解ãååŸãããŸãã ã³ãŒãã§ã¯ãããã¯LoadEtc1ãCompressBlockColorãMeasureHalfColorã§ãã
次ã®æé ã§ã¯ãè€éããå¢ãã¢ã«ãŽãªãºã ã䜿çšããŠæ¢åã®ãœãªã¥ãŒã·ã§ã³ã®æ¹åãè©Šã¿ãŸãã ãããã£ãŠãé«éã®CompressBlockColor44ãæåã«åŒã³åºããã次ã«äœéã®CompressBlockColor53ãåŒã³åºãããŸãã å°æ¥ã®ãã®ãããªãã§ãŒã³èšèšã«ãããå§çž®ãETC2圢åŒã«çµ±åã§ããããã«ãªããŸãã
è²æåã«ãããœãªã¥ãŒã·ã§ã³ã¯ãGuessStateColorããã³AdjustStateColoræ§é ã§è¡šãããŸãã åå·®ããŒãã«g_tableã®åå€ã«ã€ããŠãããŒãã¹ããªããã®ãšã©ãŒãèšç®ããããã£ãŒã«ãnode0ãnode1ãnode2ã«ä¿åãããŸãã ããã«ãGuessStateColorã€ã³ããã¯ã¹[0x00..0x0F]ã¯ãå¯èœãªãã¹ãŠã®ããŒã¹ã«ã©ãŒg_colors4ã®èšç®ããããšã©ãŒãæ ŒçŽããã€ã³ããã¯ã¹[0x10]ãæé©ãªãœãªã¥ãŒã·ã§ã³ã§ãã AdjustStateColorã®å Žåãæé©ãªãœãªã¥ãŒã·ã§ã³ã¯ã€ã³ããã¯ã¹[0x20]ã«æ ŒçŽãããå¯èœãªãã¹ãŠã®åºæ¬è²ã¯g_colors5ããååŸãããŸãã
ã«ã©ãŒã³ã³ããŒãã³ãã«ãããšã©ãŒèšç®ã¯ãInitLevelErrorsé¢æ°ã«ãã£ãŠä»¥åã«èšç®ãããg_errors4ãg_errors5ããŒãã«ã«åºã¥ããŠãComputeLevelãGuessLevelsãAdjustLevelsé¢æ°ã«ãã£ãŠå®è¡ãããŸãã
䞊ã¹æ¿ããé«éåããããã«ãããŒããµã€ãã§èšç®ããã䞊ã¹æ¿ããããã¯ãŒã¯ã䜿çšãããŸãã
䞊ã¹æ¿ããåã«ãèŠã€ãã£ããœãªã¥ãŒã·ã§ã³ãè¶ ãã倧ããªãšã©ãŒãç Žæ£ããããšã¯çã«ããªã£ãŠããŸãã ããã«ããããã£ãŒã«ãnode0ãnode1ãnode2ã®èŠçŽ æ°ãå€§å¹ ã«åæžããããœãŒããšåæãå€§å¹ ã«é«éåãããŸãã
ãŠã©ãŒã¯ããã³ããã æ©èœããããè¡ããŸãã
AdjustStateColoræ§é äœã§ã¯ãLazyGRã«ãã£ãŠã¯ãªã¢ãããErrorsGãErrorsGRãã£ãŒã«ããããã³ErrorsGRBãã£ãŒã«ãã«ãããããã©ãŒãã³ã¹ãå€§å¹ ã«åäžããŸãã
_mm_adds_epu8ããã³_mm_subs_epu8ã³ãã³ãã¯ãããŒã¹ã«ã©ãŒãšåå·®ãã4è²ãã¬ãããèšç®ããã®ã«äŸ¿å©ã§ãã
é¢æ°ComputeErrorGRBããã³ComputeErrorGRã¯ãã»ãšãã©ã®å Žåãããã深床ãååãªã®ã§ã_mm_madd_epi16ã³ãã³ãã«ãã£ãŠæé©åãããéšåçã«å±éãããã«ãŒããæåã«äœ¿çšããŸãã 倧ããªãšã©ãŒã®å Žåã2çªç®ã®ãµã€ã¯ã«ã¯ãé ãã_mm_mullo_epi32ã³ãã³ãã§æ©èœããŸãã
ComputeLevelé¢æ°ã¯ã4ã€ã®åºæ¬è²å€ã®ãšã©ãŒãäžåºŠã«èšç®ããŸãã
éæãããçµæ
äžèšã®ã¢ãããŒãã¯ãããŒããŠã§ã¢åœ¢åŒETC1ã®å§çž®ãã¯ã¹ãã£ã䜿çšããããšã«ãããAndroidããŒãžã§ã³ã®ã²ãŒã ã®RAMèŠä»¶ãåæžã§ããŸãã
ã¢ãã©ã¹ãçæããããã®ã¹ã¯ãªãããšå§çž®ãŠãŒãã£ãªãã£èªäœã¯ãã¢ãŒãã£ãã¡ã¯ããé²æ¢ããå§çž®ãããã°ã©ãã£ãã¯ã®å質ãæ¹åããåé¡ã«æ³šæãæããŸãã
é©ãã¹ãããšã«ãå§çž®ãããã°ã©ãã£ãã¯ã®å質ãæ¹åãããšãšãã«ãå§çž®èªäœãå éããããšãã§ããŸããïŒ Gardenscapesãããžã§ã¯ãã§ã¯ãIntel Core i7 6700ããã»ããµãŒã§ã¢ãã©ã¹ãETC1圢åŒã«å§çž®ããã®ã«24ç§ããããŸãã ããã¯ãã¢ãã©ã¹èªäœãçæãããããé«éã§ã以åã®é«éå§çž®ãŠãŒãã£ãªãã£ãããæ°åé«éã§ãã ææ¡ãããå¢åå§çž®ã¯19ç§ã§è¡ãããŸãã
çµè«ãšããŠãIntel Core i7 6700ããã»ããµäžã®Win64 ã®EtcCompressãŠãŒãã£ãªãã£ã«ãã£ãŠæäŸããã8192x8192 RGBãã¯ã¹ãã£ã®å§çž®äŸã瀺ããŸãã
x:\>EtcCompress Usage: EtcCompress [/retina] src [dst_color] [dst_alpha] [/debug result.png] x:\>EtcCompress 8192.png 1.etc /debug 1.png Loaded 8192.png Image 8192x8192, Texture 8192x8192 Compressed 4194304 blocks, elapsed 10988 ms, 381716 bps Saved 1.etc Texture RGB wPSNR = 42.796053, wSSIM_4x2 = 0.97524678 Saved 1.png x:\>EtcCompress 8192.png 1.etc /debug 2.png Loaded 8192.png Image 8192x8192, Texture 8192x8192 Loaded 1.etc Compressed 4194304 blocks, elapsed 6487 ms, 646570 bps Saved 1.etc Texture RGB wPSNR = 42.796053, wSSIM_4x2 = 0.97524678 Saved 2.png x:\>fc /b 1.png 2.png 1.png 2.png FC:
ãã®ãŠãŒãã£ãªãã£ãã¢ãã€ã«ã°ã©ãã£ãã¯ã¹ãå¹ççãã€è¿ éã«å§çž®ããã®ã«åœ¹ç«ã€ããšãé¡ã£ãŠããŸãã