hi gemers.
about pix_altivec functions: right now, altivec support in Gem looks like this:
<snip pix_text.h>
virtual void pix_test :: processImage(imageStruct &image); virtual void pix_test :: processImageAltivec(imageStruct &image);
</snip>
<snip pix_text.cpp>
void pix_test :: processImage(imageStruct &image) { #ifdef ALTIVEC processImageAltivec(image); return #else // some slow code #endif }
void pix_test :: processImageAltivec(imageStruct &image) { #ifdef ALTIVEC // some fast code #endif }
</snip>
now my question: wouldn't it be better to make more use of inheritance ? and call the altivec-processing directly from GemPixObj, if altivec is supported by the machine ? i write this with MMX and SSE2 in mind: i guess, all modern apple-computers have altivec; all modern pcs have mmx, but only some of them have sse2 (i guess pentium-4 only, but amd will support it in the future). i would rather decide at runtime whether any parallel processing is available, and then call the appropriate function. the fallback of all those altivec/mmx-functions would of course be the generic-processing.
so i was thinking of something like <snip GemPixObj.h>
virtual void processYUVImage(imageStruct &image); virtual void processYUVImageAltivec(imageStruct &image);
</snip> <snip GemPixObj.cpp>
void GemPixObj :: render(GemState *state){ //... switch(state->image->image.format){ //... case GL_YCBCR_422_GEM: switch (m_haveSIMD){ case SIMD_ALTIVEC: processYUVImageAltivec(state->image->image); break; default: processYUVImage(state->image->image); } //... } } void GemPixObj :: processYUVImage(imageStruct &image){ processImage(image); } void GemPixObj :: processYUVImageAltivec(imageStruct &image) processYUVImage(image); }
</snip>
<snip pix_test.h>
virtual void pix_test :: processImage(imageStruct &image); #ifdef ALTIVEC virtual void pix_test :: processImageAltivec(imageStruct &image); #endif
</snip>
<snip pix_test.cpp>
void pix_test :: processImage(imageStruct &image) { // some slow code } #ifdef ALTIVEC void pix_test :: processImageAltivec(imageStruct &image) { // some fast code } #endif
</snip>
GemPixObj::m_haveSIMD could be SIMD_ALTIVEC, SIMD_MMX, SIMD_SSE2 (or whatever)
pros (i can think of right now): code that is the same is rather in the parent-class than in each child. this would make it possible to turn on/off SIMD on the fly. (probably not a very good argument, but handy for profiling / showing the advantages of SIMD). furthermore it would keep the #ifdef-nightmare a bit more clean ( i believe) the number of function-calls would be reduced by one (at the cost of one case-loop)
i don't know whether G5-ALTIVEC-compiles can be executed on G4's - would it be possible if the PPC970-code would be capsuled in an if-clause ?
drawbacks: - a little work to be done (i have already started to do so, but haven't yet committed it because i don't know, whether my idea is really good) - there has to be a naming scheme for SIMD-processing. i have noticed, that in PixDualObj's the naming is rather arbitrary: pix_subtract::processYUVAltivec() vs. pix_chroma_key::processYUV_YUVAltivec()
any comments ?
mfg.as.r IOhannes
Quoting IOhannes m zmoelnig zmoelnig@iem.at:
now my question: wouldn't it be better to make more use of inheritance ? and call the altivec-processing directly from GemPixObj, if altivec is
supported by the machine ? i write this with MMX and SSE2 in mind: i guess, all modern apple-computers have altivec; all modern pcs have mmx, but only some of them have sse2 (i guess pentium-4 only, but amd will support it in the future). i would rather decide at runtime whether any parallel processing is available, and then call the appropriate function. the fallback of all
those altivec/mmx-functions would of course be the generic-processing.
The big problem with run-time checking is that all modern processors have branch prediction so that when a conditional is reached it will speculatively execute a part of each branch. If one branch has a SIMD instruction that the machine can't handle then the app will segfault with an illegal instruction. Only if that condition can be absolutely assured never to happen will run-time checking work (and you have to really, really enjoy debugging random crashes too).
The only way that I've seen people do this is runtime module loading like in Photoshop.
i don't know whether G5-ALTIVEC-compiles can be executed on G4's - would it be possible if the PPC970-code would be capsuled in an if-clause ?
Certain instructions (vec_dst) have to be avoided on the G5/970 because they are software prefetch ops that over-ride the built in hardware prefetch in the 970 which serializes instructions until the op is complete. That's some bad news. I've made an ifdef for this, which also avoids the nasty branch prediction and OOOE (Out-of-order-Execution) issue.
that in PixDualObj's the naming is rather arbitrary: pix_subtract::processYUVAltivec() vs. pix_chroma_key::processYUV_YUVAltivec()
pix_chroma_key is a dual pix object and follows the YUV_YUV convention of the other dualPix objects. There could be a RGB_YUV oro YUV_RGB version at some point (who knows?).
cgc
cgc@humboldtblvd.com wrote:
The big problem with run-time checking is that all modern processors have branch prediction so that when a conditional is reached it will speculatively execute a part of each branch. If one branch has a SIMD instruction that the machine can't handle then the app will segfault with an illegal instruction.
so we cannot use SIMD-compiled code for non-simd machines (if the compiler does not support compilation into SIMD/non-SIMD code: the intel-compiler should support this at least) but of course we can have the generic procedures live next the SIMD-procedures without any problem (on SIMD-platforms). i think it would be easier to code, if you would only have to #ifdef the core altivec function and not worry about the generic function.
The only way that I've seen people do this is runtime module loading like in Photoshop.
which would be a lot to administer...
that in PixDualObj's the naming is rather arbitrary: pix_subtract::processYUVAltivec() vs. pix_chroma_key::processYUV_YUVAltivec()
pix_chroma_key is a dual pix object and follows the YUV_YUV convention of the other dualPix objects. There could be a RGB_YUV oro YUV_RGB version at some point (who knows?).
it was rather the pix_subtract i had in mind with inconsistency. anyhow, bot are pix dual objects processing two YUV-images and the naming scheme is different. just for not forgetting about it.
cgc
anyhow, my changes up till now are only <old> pix_test::processAltivec(){ #ifdef ALTIVEC ... #endif } </old> <new> #ifdef ALTIVEC pix_test::processAltivec(){ ... } #endif
so i think i can safely submit these. (but what for ?;-))
mfg.,as.rd IOhannes