این رشته مقالات ترجمه ای از The Book of Shaders میباشد، که نگاهی عمیق و قدم به قدم در مورد شیدر نویسی در گرافیک کامپیوتری هست.
اگر تجربه نقاشی در کامپیوتر را داشته باشید میدانید که در این فرایند، دایره، مستطیل و خط هارا یکی پس از دیگری میکشید تا شکل مورد نظر خود را نهایی کنید، این فرایند شبیه نوشتن کتاب است، در واقع این کار ها مجموعه ای از دستور العمل ها هستند که وظایف را یکی پس از دیگری انجام میدهند.
شیدر ها هم مجموعه ای از دستور العمل ها هستند، اما دستور المل هایی که به یکباره برای هر پیکسل روی صفحه اجرا میشود. این بدان معناست، کدی که مینویسید بسته به موقعیت پیکسل روی صفحه نمایش باید رفتار متفاوتی انجام دهد. برنامه شما مانند تابعی کار میکند که موقعیت را دریافت میکند و یک رنگ را بر میگرداند، زمانی که کد شما کامپایل میشود، این عملیات بسیار سریع انجام میشود.
برای پاسخ به این سوال من شگفتی پردازش موازی را به شما معرفی میکنم.
پردازه مرکزی(CPU) رایانه خود را به عنوان یک لوله بزرگ صنعتی در نظر بگیرید، و هر تسکی را مانند چیزی که از داخل آن عبور میکند بپندارید. بعضی تسک ها بزرگ تر از بقیه هستند پس زمان و انرژی بیشتری برای پردازش آن ها نیاز است. به نوعی میگوییم این نوع تسک ها به قدرت پردازش بالاتری نیاز دارند. به دلیل معماری رایانه ها تسک ها مجبور هستند به صورت سری اجرا شوند، تسک ها باید یک به یک تمام شوند. رایانه های مدرن معمولا دارای گروه های چهارتایی از پردازنده ها هستند، که مانند این لوله ها کار میکنند و وظایف را یکی پس از دیگری انجام میدهد تا کار ها بدون مشکل انجام شود، هر لوله را به عنوان یک ترد(thread) هم میشناسند.
بازی های ویدئویی و سایر برنامه های گرافیکی به پردازش بیشتری نسبت به برنامه های معمول نیاز دارند. به دلیل محتویات زیاد، آن ها باید باید مقادیر زیادی عملیات پیکسل به پیکسل انجام دهند. هر یک از پیکسل ها باید محاسبه شوند، همچنین در بازی های سه بعدی باید عملیات های بیشتری مثل محاسبات هندسی و پرسپکتیو هم انجام شود.
بیاید به استعاره خود در مورد لوله ها و تسک ها برگردیم، هر پیکسل رو صفحه نمایش یک تسک کوچک و ساده را نشان میدهد، به طور جداگانه تسک هر پیکسل برای CPU مسئله ای نیست. اما اینکه این تسک های کوچک باید برای هر پیکسل انجام شود برای CPU مشکل ساز است. این یعنی در صفحات قدیمی 800x600 باید 480,000 پیکسل در هر فریم پردازش شود که به معنی 14,400,000 محاسبه در ثانیه است! بله این مقدار به قدری بزرگ هست که یک ریزپردازنه را سرریز کند. در یک نمایشگر مدرن 2880x1800 با نرخ 60 فریم بر ثانیه، این محاسبات به 311,040,000 محاسبه در ثانیه میرسد. چگونه مهندسان گرافیک این مشکل را حل میکنند؟
این زمانی است که پردازش موازی به یک راه حل خوب تبدیل میشود، منطقی است که به جای داشتن چند ریز پردازنده بزرگ یا قدرتمند(لوله)، ریزپردازنده های کوچکتری و بیشتری به صورت موازی کار کنند.
واحد پردازنده گرافیکی(GPU) همین طور عمل میکند.
ریز پردازنده های کوچک را مانند جدولی از لوله ها وداده های هر پیکسل را مانند یک توپ تصور کنید، 14,400,000 توپ میتواند هر لوله های را مسدود کند، اما میتوان یک جدول از 800x600 لوله کوچک را که 30 موج 480,000 تایی پیکسل در ثانیه دریافت میکند را به راحتی کنترل کرد. در وضوح بالاتر هم به همین صورت عمل میکند. هرچه سخت افزار های موازی بیشتری داشته باشید، به همان نسبت جریان بیشتری را میتوانید مدیریت کنید.
از دیگر قدرت های فوق العاده GPU عملکرد های ویژه ریاضی آن است که از طریق سخت افزار سریع تر میشود، یعنی این عملیات ریاضی به جای استفاده از نرم افزار مستقیما توسط میکرو تراشه حل میشوند، به عبارتی عملکرد های مثلثاتی و ماتریسی به سرعت الکتریسیته میتواندد سریع باشند.
مخفف OpenGL Shading Language است. که استانداری خاص از برنامه های شیدر هست و در فصل بعدی خواهید دید. بسته به سخت افزار و سیستم عامل ها انواع دیگر شیدر نیز وجود دارند. در اینجا ما با OpenGL تنظیم شده توسط گروه Khronos کار خواهیم کرد. دانستن تاریخچه OpenGL میتواند به درک بیشتر قرار داد های عجیب و غریب آن مفید باشد، برای همین توصیه میکنیم نگاهی به این موضوع داشته باشید: openglbook.com/chapter-0-preface-what-is-opengl.html
همانطور که عمو بن گفت:"قدرت زیاد، با مسئولیت بزرگی همراه است"، و محاسبه موازی ازین قاعده پیروی میکند، طراحی معماری قوی GPU محدودیت ها و خصوصیات مخصوص به خودش را دارد.
برای این که به صورت موازی هر لوله یا ترد اجرا شود. باید از هر ترد دیگری مستقل باشد، ترد ها نسبت به آنچه بقیه ترد ها انجام میدهد نا آگاه هستند. این محدودیت نشان میدهد که همه داده ها باید در یک جهت جریان داشته باشند. پس بررسی نتیجه یک ترد دیگر، اصلاح داده های ورودی و یا انتقال نتیجه یک ترد به ترد دیگر غیر ممکن است. اگر به ترد ها اجازه ارتباط داده شود، یکپارچگی داده ها در معرض خطر قرار خواهد گرفت.
همچنین GPU پردازنده های موازی را به طور مداوم مشغول نگه میدارد، به محض اینکه آزاد میشوند، داده های جدید برای پردازش دریافت میکنند. برای یک ترد غیر ممکن است که بداند که لحظه قبلی چه کاری انجام داده. عملیات قبلی آن میتواند کشیدن یک دکمه برای UI سیستم عامل بوده باشد یا رندر یک آسمان در بازی ویدئویی. هر ترد نه تنها کور(Blind) است(نا آگاه از عملیات ترد های دیگر) بلکه بی حافظه نیز هست. علاوه بر دانستن مفهوم نحوه کد نویسی بر اساس موقعیت هر پیکسل، این کور بودن و بی حافظه بودن، باعث میشود، شیدر ها در میان برنامه نویسان تازه محبوبیت نداشته باشد.
نگران نباش در فصل های بعد، گام به گام یاد خواهیم گرفت چگونه محاسبات ساده تا پیشرفته شیدر را انجام دهیم.