| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- /******************************************************************************/
- #include "stdafx.h"
- namespace EE{
- /******************************************************************************/
- enum IMAGE_TYPE_CREATE_RESULT : Byte
- {
- UNKNOWN,
- FAILED ,
- SUCCESS,
- };
- static IMAGE_TYPE_CREATE_RESULT ImageTypeCreateResult[2][IMAGE_ALL_TYPES]; // [MultiSample][IMAGE_TYPE]
- struct ImageRTType
- {
- IMAGE_TYPE types[6]; // 6 is max IMAGE_TYPE elms per ImageRTType
- };
- static const ImageRTType ImageRTTypes[]=
- {
- {IMAGE_DEFAULT }, // 0 IMAGERT_RGBA
- {IMAGE_R10G10B10A2 , IMAGE_DEFAULT }, // 1 IMAGERT_RGB
- {IMAGE_R10G10B10A2 , IMAGE_F16_3, IMAGE_F16_4, IMAGE_DEFAULT }, // 2 IMAGERT_RGB_P
- {IMAGE_F16_4 , IMAGE_DEFAULT }, // 3 IMAGERT_RGBA_H
- {IMAGE_F16_3 , IMAGE_F16_4, IMAGE_R10G10B10A2, IMAGE_DEFAULT }, // 4 IMAGERT_RGB_H
- {IMAGE_F32_4 , IMAGE_F16_4, IMAGE_DEFAULT }, // 5 IMAGERT_RGBA_F
- {IMAGE_F32_3 , IMAGE_F32_4, IMAGE_F16_3, IMAGE_F16_4, IMAGE_R10G10B10A2, IMAGE_DEFAULT}, // 6 IMAGERT_RGB_F
- {IMAGE_R8G8B8A8_SIGN, IMAGE_F16_4 }, // 7 IMAGERT_RGBA_S
- {IMAGE_F32 , IMAGE_F16 }, // 8 IMAGERT_F32
- {IMAGE_F16 , IMAGE_F32 }, // 9 IMAGERT_F16
- {
- #if DX9
- IMAGE_A8, IMAGE_L8A8,
- #else
- IMAGE_R8, IMAGE_R8G8,
- #endif
- IMAGE_DEFAULT}, // 10 IMAGERT_ONE
- {
- #if !DX9
- IMAGE_R8_SIGN, IMAGE_R8G8_SIGN,
- #endif
- IMAGE_F16,
- #if !DX9
- IMAGE_R8G8B8A8_SIGN,
- #endif
- IMAGE_F32}, // 11 IMAGERT_ONE_S
- {
- #if !DX9
- IMAGE_R8G8,
- #endif
- IMAGE_DEFAULT}, // 12 IMAGERT_TWO
- {
- #if !DX9
- IMAGE_R8G8_SIGN, IMAGE_R8G8B8A8_SIGN,
- #endif
- IMAGE_F16_2}, // 13 IMAGERT_TWO_S
- {
- #if DX9
- IMAGE_INTZ, /*IMAGE_RAWZ, */IMAGE_DF24, // read why IMAGE_RAWZ is disabled in 'RendererClass::rtCreate()'
- #endif
- IMAGE_D24S8, IMAGE_D24X8, IMAGE_D32, IMAGE_D16}, // 14 IMAGERT_DS
- }; ASSERT(IMAGERT_RGBA==0 && IMAGERT_RGB==1 && IMAGERT_RGB_P==2 && IMAGERT_RGBA_H==3 && IMAGERT_RGB_H==4 && IMAGERT_RGBA_F==5 && IMAGERT_RGB_F==6 && IMAGERT_RGBA_S==7 && IMAGERT_F32==8 && IMAGERT_F16==9 && IMAGERT_ONE==10 && IMAGERT_ONE_S==11 && IMAGERT_TWO==12 && IMAGERT_TWO_S==13 && IMAGERT_DS==14 && IMAGERT_NUM==15);
- static ImageRTType ImageRTTypesOK[2][Elms(ImageRTTypes)]; // [MultiSample][IMAGERT_NUM], this keeps info about result of creating different IMAGE_TYPE for 1-sample and multi-sample, this is because some formats may fail to create multi-sampled but succeed with 1-sample (for simplication this assumes that there will be only one type of multi-sample, like only 4x, but not 4x and 8x)
- static CChar8 *ImageRTName[]=
- {
- "RGBA" , // 0
- "RGB" , // 1
- "RGB_P" , // 2
- "RGBA_H", // 3
- "RGB_H" , // 4
- "RGBA_F", // 5
- "RGB_F" , // 6
- "RGBA_S", // 7
- "F32" , // 8
- "F16" , // 9
- "ONE" , // 10
- "ONE_S" , // 11
- "TWO" , // 12
- "TWO_S" , // 13
- "DS" , // 14
- }; ASSERT(IMAGERT_RGBA==0 && IMAGERT_RGB==1 && IMAGERT_RGB_P==2 && IMAGERT_RGBA_H==3 && IMAGERT_RGB_H==4 && IMAGERT_RGBA_F==5 && IMAGERT_RGB_F==6 && IMAGERT_RGBA_S==7 && IMAGERT_F32==8 && IMAGERT_F16==9 && IMAGERT_ONE==10 && IMAGERT_ONE_S==11 && IMAGERT_TWO==12 && IMAGERT_TWO_S==13 && IMAGERT_DS==14 && IMAGERT_NUM==15);
- /******************************************************************************/
- static const IMAGERT_TYPE GetImageRTTypeLookup[IMAGE_PRECISION_NUM][2]= // [precision][alpha]
- {
- // no alpha , alpha
- {IMAGERT_RGB , IMAGERT_RGBA }, // 0 IMAGE_PRECISION_8
- {IMAGERT_RGB_P, IMAGERT_RGBA_P}, // 1 IMAGE_PRECISION_10
- {IMAGERT_RGB_H, IMAGERT_RGBA_H}, // 2 IMAGE_PRECISION_16
- {IMAGERT_RGB_F, IMAGERT_RGBA_F}, // 3 IMAGE_PRECISION_24
- {IMAGERT_RGB_F, IMAGERT_RGBA_F}, // 4 IMAGE_PRECISION_32
- {IMAGERT_RGB_F, IMAGERT_RGBA_F}, // 5 IMAGE_PRECISION_64
- }; ASSERT(IMAGE_PRECISION_8==0 && IMAGE_PRECISION_10==1 && IMAGE_PRECISION_16==2 && IMAGE_PRECISION_24==3 && IMAGE_PRECISION_32==4 && IMAGE_PRECISION_64==5 && IMAGE_PRECISION_NUM==6);
- IMAGERT_TYPE GetImageRTType( Bool alpha, IMAGE_PRECISION precision) {return GetImageRTTypeLookup[precision][alpha];}
- IMAGERT_TYPE GetImageRTType(IMAGE_TYPE type, Bool allow_alpha, IMAGE_PRECISION max_precision)
- {
- if(type==IMAGE_R10G10B10A2)return IMAGERT_RGB; // because the implementation operates on Bool alpha (yes/no) and not how many alpha bits we want, then as result we may actually increase precision when operating on 'IMAGE_R10G10B10A2' with 'allow_alpha'=true, so treat this as a special case and always return IMAGERT_RGB
- C ImageTypeInfo &ti=ImageTI[type]; return GetImageRTType(ti.a && allow_alpha, Min(ti.precision, max_precision));
- }
- IMAGERT_TYPE GetImageRTType(IMAGE_TYPE type, Bool allow_alpha)
- {
- if(type==IMAGE_R10G10B10A2)return IMAGERT_RGB; // because the implementation operates on Bool alpha (yes/no) and not how many alpha bits we want, then as result we may actually increase precision when operating on 'IMAGE_R10G10B10A2' with 'allow_alpha'=true, so treat this as a special case and always return IMAGERT_RGB
- C ImageTypeInfo &ti=ImageTI[type]; return GetImageRTType(ti.a && allow_alpha, ti.precision);
- }
- IMAGERT_TYPE GetImageRTType(IMAGE_TYPE type)
- {
- if(type==IMAGE_R10G10B10A2)return IMAGERT_RGB; // because the implementation operates on Bool alpha (yes/no) and not how many alpha bits we want, then as result we may actually increase precision when operating on 'IMAGE_R10G10B10A2', so treat this as a special case and always return IMAGERT_RGB
- C ImageTypeInfo &ti=ImageTI[type]; return GetImageRTType(ti.a>0, ti.precision);
- }
- /******************************************************************************/
- void ResetImageTypeCreateResult()
- {
- Zero(ImageTypeCreateResult); ASSERT(UNKNOWN==0); // assume that all are UNKNOWN (zero)
- CopyFast(ImageRTTypesOK[0], ImageRTTypes);
- CopyFast(ImageRTTypesOK[1], ImageRTTypes);
- }
- static Int CompareDesc(C ImageRC &image, C ImageRTDesc &desc)
- {
- if(Int c=Compare(image.w (), desc.size.x ))return c;
- if(Int c=Compare(image.h (), desc.size.y ))return c;
- if(Int c=Compare(image.type (), desc._type ))return c;
- if(Int c=Compare(image.samples(), desc.samples))return c;
- return 0;
- }
- static inline Bool ImageRTCreate(ImageRC &image, C ImageRTDesc &desc)
- {
- Bool ok;
- if(ImageTI[desc._type].d) // if this is a depth buffer
- {
- ok=image.createTryEx(desc.size.x, desc.size.y, 1, desc._type, IMAGE_DS_RT, 1, desc.samples); // try first as a render target
- #if DX9 || GL // for DX10+ IMAGE_DS_RT is the same as IMAGE_DS so don't bother checking it again
- if(!ok)ok=image.createTryEx(desc.size.x, desc.size.y, 1, desc._type, IMAGE_DS , 1, desc.samples);
- #endif
- }else
- {
- ok=image.createTryEx(desc.size.x, desc.size.y, 1, desc._type, IMAGE_RT, 1, desc.samples);
- }
- if(ok)Time.skipUpdate();
- return ok;
- }
- static inline void Set(ImageRTPtr &p, ImageRC &rt) // this is called only when "_ptr_num==0"
- {
- rt._ptr_num++; p._data=&rt; rt.discard();
- }
- ImageRTPtr& ImageRTPtr::clear()
- {
- if(_data)
- {
- DEBUG_ASSERT(_data->_ptr_num, "ImageRC._ptr_num should be >0");
- _data->_ptr_num--;
- if(!_data->_ptr_num)_data->discard();
- _data=null;
- }
- return T;
- }
- ImageRTPtr& ImageRTPtr::operator=(C ImageRTPtr &p)
- {
- if(T!=p)
- {
- clear();
- if(T._data=p._data){T._data->_ptr_num++; T._last_index=p._last_index;} // assign to new
- }
- return T;
- }
- ImageRTPtr& ImageRTPtr::operator=(ImageRC *p)
- {
- if(T!=p)
- {
- clear();
- if(T._data=p)T._data->_ptr_num++; // assign to new
- }
- return T;
- }
- ImageRTPtr::ImageRTPtr(C ImageRTPtr &p)
- {
- if(T._data=p._data){T._data->_ptr_num++; T._last_index=p._last_index;}else T._last_index=-1;
- }
- ImageRTPtr::ImageRTPtr(ImageRC *p)
- {
- if(T._data=p)T._data->_ptr_num++;else T._last_index=-1;
- }
- /******************************************************************************/
- Bool ImageRTPtr::find(C ImageRTDesc &desc)
- {
- clear(); // clear first so we can find the same Image if possible
- Bool multi_sample =(desc.samples>1);
- IMAGE_TYPE_CREATE_RESULT (&itcr)[IMAGE_ALL_TYPES]=ImageTypeCreateResult[multi_sample];
- ImageRTType &types =ImageRTTypesOK [multi_sample][desc.rt_type];
- again:
- ConstCast(desc._type)=types.types[0];
- Bool found; if(InRange(_last_index, Renderer._rts) && !CompareDesc(Renderer._rts[_last_index], desc))found=true; // in range and matches ("!CompareDesc" -> match)
- else found=Renderer._rts.binarySearch(desc, _last_index, CompareDesc);
- if(found)
- {
- // check '_last_index' first
- ImageRC &rt=Renderer._rts[_last_index];
- if(rt.available()){Set(T, rt); return true;}
- // check all neighbors with the same desc
- for(Int i=_last_index-1; i>=0 ; i--) {ImageRC &rt=Renderer._rts[i]; if(CompareDesc(rt, desc))break; if(rt.available()){Set(T, rt); T._last_index=i; return true;}}
- for(Int i=_last_index+1; InRange(i, Renderer._rts); i++) {ImageRC &rt=Renderer._rts[i]; if(CompareDesc(rt, desc))break; if(rt.available()){Set(T, rt); T._last_index=i; return true;}}
- }
- switch(itcr[desc._type])
- {
- case UNKNOWN:
- {
- ImageRC temp; Bool ok=ImageRTCreate(temp, desc); // try to create first as a standalone variable (not in 'Renderer._rts') in case it fails so we don't have to remove it
- itcr[desc._type]=(ok ? SUCCESS : FAILED);
- if(ok){ImageRC &rt=Renderer._rts.NewAt(_last_index); Swap(rt, temp); Set(T, rt); return true;}
- // fail
- if(desc._type!=IMAGE_NONE)
- {
- MoveFastN(&types.types[0], &types.types[1], ELMS(types.types)-1); // move all elements from index 1 and right, to the left by 1, to index 0..
- types.types[ELMS(types.types)-1]=IMAGE_NONE; // set last type as none
- if(types.types[0]!=IMAGE_NONE)goto again; // try the new type
- }
- }break;
- case SUCCESS:
- {
- ImageRC &rt=Renderer._rts.NewAt(_last_index); if(!ImageRTCreate(rt, desc))Exit(S+"Can't create Render Target "+desc.size.x+'x'+desc.size.y); // Exit because SUCCESS always assumes to succeed
- Set(T, rt); return true;
- }break;
- }
- return false;
- }
- /******************************************************************************/
- ImageRTPtr& ImageRTPtr::get(C ImageRTDesc &desc)
- {
- if(!find(desc))Exit(S+"Can't create Render Target "+desc.size.x+'x'+desc.size.y+' '+ImageRTName[desc.rt_type]+", samples:"+desc.samples);
- return T;
- }
- ImageRTPtr& ImageRTPtr::getDS(Int w, Int h, Byte samples, Bool reuse_main)
- {
- clear(); // clear first so we can find the same Image if possible
- if(reuse_main)
- {
- ImageRC &ds=Renderer._main_ds, *cur_ds=Renderer._cur_main_ds;
- #if GL
- // on OpenGL we can't reuse '_main_ds' because it has different flipping orientation as it is always paired with '_main' in the main FBO
- // <- here don't check for 'ds'
- if(cur_ds==&ds)cur_ds=null; // if 'cur_ds' is 'ds' then don't check it either
- #else
- if( /*ds .available() && */ ds .accessible() && ds .w()==w && ds .h()==h && ds .samples()==samples){T= &ds; return T;} // if ds is not used (actually don't check this because '_gui_ds' can be set to it at the start of each frame), accessible and compatible then we can use it
- #endif
- if(cur_ds && /*cur_ds->available() && */cur_ds->accessible() && cur_ds->w()==w && cur_ds->h()==h && cur_ds->samples()==samples){T=cur_ds; return T;} // if ds is not used (actually don't check this because '_gui_ds' can be set to it at the start of each frame), accessible and compatible then we can use it
- }
- get(ImageRTDesc(w, h, IMAGERT_DS, samples)); return T;
- }
- /******************************************************************************/
- Bool ImageRTPtr::find(Int w, Int h, IMAGERT_TYPE rt_type, Byte samples) {return find(ImageRTDesc(w, h, rt_type, samples));}
- ImageRTPtr& ImageRTPtr:: get(Int w, Int h, IMAGERT_TYPE rt_type, Byte samples) {return get(ImageRTDesc(w, h, rt_type, samples));}
- /******************************************************************************/
- }
- /******************************************************************************/
|